mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 07:57:21 +08:00
refactor: 替换验证器
This commit is contained in:
11
.mockery.yaml
Normal file
11
.mockery.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
with-expecter: True
|
||||
disable-version-string: True
|
||||
dir: mocks/{{ replaceAll .InterfaceDirRelative "internal" "" }}
|
||||
mockname: "{{.InterfaceName}}"
|
||||
outpkg: "{{.PackageName}}"
|
||||
filename: "{{.InterfaceName}}.go"
|
||||
all: True
|
||||
packages:
|
||||
github.com/TheTNB/panel/internal/biz:
|
||||
config:
|
||||
recursive: True
|
||||
7
go.mod
7
go.mod
@@ -10,9 +10,6 @@ require (
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/go-chi/chi/v5 v5.1.0
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.3
|
||||
github.com/go-playground/locales v0.14.1
|
||||
github.com/go-playground/universal-translator v0.18.1
|
||||
github.com/go-playground/validator/v10 v10.23.0
|
||||
github.com/go-rat/chix v1.1.4
|
||||
github.com/go-rat/gormstore v1.0.6
|
||||
github.com/go-rat/sessions v1.0.11
|
||||
@@ -21,6 +18,7 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/golang-cz/httplog v0.0.0-20241002114323-98e09d6f537a
|
||||
github.com/gomodule/redigo v1.9.2
|
||||
github.com/gookit/validate v1.5.3
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/hashicorp/go-version v1.7.0
|
||||
github.com/knadh/koanf/parsers/yaml v0.1.0
|
||||
@@ -62,11 +60,12 @@ require (
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/gofiber/schema v1.2.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gookit/filter v1.2.1 // indirect
|
||||
github.com/gookit/goutil v0.6.18 // indirect
|
||||
github.com/jaevor/go-nanoid v1.4.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
|
||||
20
go.sum
20
go.sum
@@ -32,14 +32,6 @@ github.com/go-gormigrate/gormigrate/v2 v2.1.3 h1:ei3Vq/rpPI/jCJY9mRHJAKg5vU+EhZy
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.3/go.mod h1:VJ9FIOBAur+NmQ8c4tDVwOuiJcgupTG105FexPFrXzA=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
|
||||
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-rat/chix v1.1.4 h1:YVDwF4vrlkm5hmlDGWKoiWPgP98pJooBvhsto8UWq+o=
|
||||
github.com/go-rat/chix v1.1.4/go.mod h1:eKUTG7GXqMS278PH0QZi8yMWZddvMfxqWu7mverM6kQ=
|
||||
github.com/go-rat/gormstore v1.0.6 h1:YxmaY6n3JoTk6o9RXoZ1+cQ6HQL+ayf/6d8D76ydCAc=
|
||||
@@ -70,6 +62,14 @@ github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlG
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
||||
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
|
||||
github.com/gookit/filter v1.2.1 h1:37XivkBm2E5qe1KaGdJ5ZfF5l9NYdGWfLEeQadJD8O4=
|
||||
github.com/gookit/filter v1.2.1/go.mod h1:rxynQFr793x+XDwnRmJFEb53zDw0Zqx3OD7TXWoR9mQ=
|
||||
github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
|
||||
github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=
|
||||
github.com/gookit/validate v1.5.3 h1:czD1H+fcOJX+dfY0vzjHSMb+jrKTMeI8Fhu59ZMIB9o=
|
||||
github.com/gookit/validate v1.5.3/go.mod h1:1OfvI1eGJqSODHERKdxvPGcconT4eTvVLmYt1A3QZlI=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
@@ -94,8 +94,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ=
|
||||
@@ -151,6 +149,8 @@ github.com/tufanbarisyildirim/gonginx v0.0.0-20241205102811-323481085fb4 h1:p5dI
|
||||
github.com/tufanbarisyildirim/gonginx v0.0.0-20241205102811-323481085fb4/go.mod h1:hdMWBc1+TyB6G5ZZBBgPWQ8cjRZ6zpYdhal0uu6E9QM=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/go-rat/sessions"
|
||||
"github.com/go-rat/utils/crypt"
|
||||
"github.com/knadh/koanf/v2"
|
||||
@@ -16,16 +14,14 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
Conf *koanf.Koanf
|
||||
Http *chi.Mux
|
||||
Orm *gorm.DB
|
||||
Validator *validator.Validate
|
||||
Translator *ut.Translator
|
||||
Session *sessions.Manager
|
||||
Cron *cron.Cron
|
||||
Queue *queue.Queue
|
||||
Logger *slog.Logger
|
||||
Crypter crypt.Crypter
|
||||
Conf *koanf.Koanf
|
||||
Http *chi.Mux
|
||||
Orm *gorm.DB
|
||||
Session *sessions.Manager
|
||||
Cron *cron.Cron
|
||||
Queue *queue.Queue
|
||||
Logger *slog.Logger
|
||||
Crypter crypt.Crypter
|
||||
)
|
||||
|
||||
// 面板状态常量
|
||||
|
||||
@@ -19,7 +19,6 @@ func boot() {
|
||||
|
||||
func BootWeb() {
|
||||
boot()
|
||||
initValidator()
|
||||
initSession()
|
||||
initQueue()
|
||||
initCron()
|
||||
|
||||
@@ -1,30 +1,15 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/go-playground/locales/zh_Hans_CN"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/go-playground/validator/v10/translations/zh"
|
||||
|
||||
"github.com/TheTNB/panel/internal/app"
|
||||
"github.com/TheTNB/panel/internal/http/rule"
|
||||
"github.com/gookit/validate"
|
||||
"github.com/gookit/validate/locales/zhcn"
|
||||
)
|
||||
|
||||
func initValidator() {
|
||||
translator := zh_Hans_CN.New()
|
||||
uni := ut.New(translator, translator)
|
||||
trans, _ := uni.GetTranslator("zh_Hans_CN")
|
||||
|
||||
validate := validator.New(validator.WithRequiredStructEnabled())
|
||||
if err := zh.RegisterDefaultTranslations(validate, trans); err != nil {
|
||||
log.Fatalf("failed to register validator translations: %v", err)
|
||||
}
|
||||
|
||||
app.Translator = &trans
|
||||
app.Validator = validate
|
||||
if err := rule.RegisterRules(validate); err != nil {
|
||||
log.Fatalf("failed to register validator rules: %v", err)
|
||||
}
|
||||
func init() {
|
||||
zhcn.RegisterGlobal()
|
||||
validate.Config(func(opt *validate.GlobalOption) {
|
||||
opt.StopOnError = false
|
||||
opt.SkipOnEmpty = true
|
||||
opt.FieldTag = "form"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ type WithRules interface {
|
||||
Rules(r *http.Request) map[string]string
|
||||
}
|
||||
|
||||
type WithFilters interface {
|
||||
Filters(r *http.Request) map[string]string
|
||||
}
|
||||
|
||||
type WithMessages interface {
|
||||
Messages(r *http.Request) map[string]string
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@ package rule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Exists 验证一个值在某个表中的字段中存在,支持同时判断多个字段
|
||||
// Exists verify a value exists in a table field, support judging multiple fields at the same time
|
||||
// 用法:exists:表名称,字段名称,字段名称,字段名称
|
||||
// Usage: exists:table_name,field_name,field_name,field_name
|
||||
// 例子:exists:users,phone,email
|
||||
// Example: exists:users,phone,email
|
||||
type Exists struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
@@ -16,20 +20,17 @@ func NewExists(db *gorm.DB) *Exists {
|
||||
return &Exists{DB: db}
|
||||
}
|
||||
|
||||
// Exists 格式 `exists=categories id other_field`
|
||||
func (r *Exists) Exists(fl validator.FieldLevel) bool {
|
||||
requestValue := fl.Field().Interface()
|
||||
params := strings.Fields(fl.Param())
|
||||
if len(params) < 2 {
|
||||
func (r *Exists) Passes(val any, options ...any) bool {
|
||||
if len(options) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
tableName := params[0]
|
||||
fieldNames := params[1:]
|
||||
tableName := options[0].(string)
|
||||
fieldNames := options[1:]
|
||||
|
||||
query := r.DB.Table(tableName).Where(fmt.Sprintf("%s = ?", fieldNames[0]), requestValue)
|
||||
query := r.DB.Table(tableName).Where(fmt.Sprintf("%s = ?", fieldNames[0]), val)
|
||||
for _, fieldName := range fieldNames[1:] {
|
||||
query = query.Or(fmt.Sprintf("%s = ?", fieldName), requestValue)
|
||||
query = query.Or(fmt.Sprintf("%s = ?", fieldName), val)
|
||||
}
|
||||
|
||||
var count int64
|
||||
|
||||
@@ -2,12 +2,16 @@ package rule
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// NotExists 验证一个值在某个表中的字段中不存在,支持同时判断多个字段
|
||||
// NotExists verify a value does not exist in a table field, support judging multiple fields at the same time
|
||||
// 用法:not_exists:表名称,字段名称,字段名称,字段名称
|
||||
// Usage: not_exists:table_name,field_name,field_name,field_name
|
||||
// 例子:not_exists:users,phone,email
|
||||
// Example: not_exists:users,phone,email
|
||||
type NotExists struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
@@ -16,20 +20,17 @@ func NewNotExists(db *gorm.DB) *NotExists {
|
||||
return &NotExists{DB: db}
|
||||
}
|
||||
|
||||
// NotExists 格式 `not_exists=categories id other_field`
|
||||
func (r *NotExists) NotExists(fl validator.FieldLevel) bool {
|
||||
requestValue := fl.Field().Interface()
|
||||
params := strings.Fields(fl.Param())
|
||||
if len(params) < 2 {
|
||||
func (r *NotExists) Passes(val any, options ...any) bool {
|
||||
if len(options) < 2 {
|
||||
return false
|
||||
}
|
||||
|
||||
tableName := params[0]
|
||||
fieldNames := params[1:]
|
||||
tableName := options[0].(string)
|
||||
fieldNames := options[1:]
|
||||
|
||||
query := r.DB.Table(tableName).Where(fmt.Sprintf("%s = ?", fieldNames[0]), requestValue)
|
||||
query := r.DB.Table(tableName).Where(fmt.Sprintf("%s = ?", fieldNames[0]), val)
|
||||
for _, fieldName := range fieldNames[1:] {
|
||||
query = query.Or(fmt.Sprintf("%s = ?", fieldName), requestValue)
|
||||
query = query.Or(fmt.Sprintf("%s = ?", fieldName), val)
|
||||
}
|
||||
|
||||
var count int64
|
||||
|
||||
@@ -3,18 +3,18 @@ package rule
|
||||
import (
|
||||
"unicode"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
// Password 密码复杂度校验
|
||||
type Password struct{}
|
||||
|
||||
func NewPassword() *Password {
|
||||
return &Password{}
|
||||
}
|
||||
|
||||
// Password 密码复杂度校验
|
||||
func (r *Password) Password(fl validator.FieldLevel) bool {
|
||||
password := fl.Field().String()
|
||||
func (r *Password) Passes(val any, options ...any) bool {
|
||||
password := cast.ToString(val)
|
||||
// 不对空密码进行校验,有需要可以使用 required 标签
|
||||
if password == "" {
|
||||
return true
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type Regex struct{}
|
||||
|
||||
func NewRegex() *Regex {
|
||||
return &Regex{}
|
||||
}
|
||||
|
||||
func (r *Regex) Regex(fl validator.FieldLevel) bool {
|
||||
// 从标签中获取正则,格式类似于 `regex=^[a-zA-Z0-9_]+$`
|
||||
pattern := fl.Param()
|
||||
// 替换转义字符
|
||||
pattern = strings.ReplaceAll(pattern, ",", ",")
|
||||
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
value := fl.Field().String()
|
||||
return re.MatchString(value)
|
||||
}
|
||||
@@ -1,66 +1,19 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/TheTNB/panel/internal/app"
|
||||
"github.com/gookit/validate"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func RegisterRules(v *validator.Validate) error {
|
||||
if err := v.RegisterValidation("exists", NewExists(app.Orm).Exists); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterValidation("not_exists", NewNotExists(app.Orm).NotExists); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterValidation("regex", NewRegex().Regex); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterValidation("password", NewPassword().Password); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.RegisterTranslation("exists", *app.Translator,
|
||||
func(ut ut.Translator) error {
|
||||
return ut.Add("exists", "{0} 不存在", true)
|
||||
},
|
||||
func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("exists", fe.Field())
|
||||
return t
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterTranslation("not_exists", *app.Translator,
|
||||
func(ut ut.Translator) error {
|
||||
return ut.Add("not_exists", "{0} 已存在", true)
|
||||
},
|
||||
func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("not_exists", fe.Field())
|
||||
return t
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterTranslation("regex", *app.Translator,
|
||||
func(ut ut.Translator) error {
|
||||
return ut.Add("regex", "{0} 格式不正确", true)
|
||||
},
|
||||
func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("regex", fe.Field())
|
||||
return t
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.RegisterTranslation("password", *app.Translator,
|
||||
func(ut ut.Translator) error {
|
||||
return ut.Add("password", "密码不满足要求(8-20位,至少包含字母、数字、特殊字符中的两种)", true)
|
||||
},
|
||||
func(ut ut.Translator, fe validator.FieldError) string {
|
||||
t, _ := ut.T("password")
|
||||
return t
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
func GlobalRules(db *gorm.DB) {
|
||||
validate.AddValidators(validate.M{
|
||||
"exists": NewExists(db).Passes,
|
||||
"not_exists": NewNotExists(db).Passes,
|
||||
"password": NewPassword().Passes,
|
||||
})
|
||||
validate.AddGlobalMessages(map[string]string{
|
||||
"exists": "{field} 不存在",
|
||||
"not_exists": "{field} 已存在",
|
||||
"password": "密码不满足要求(8-20位,至少包含字母、数字、特殊字符中的两种)",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/go-rat/chix"
|
||||
"github.com/gookit/validate"
|
||||
|
||||
"github.com/TheTNB/panel/internal/app"
|
||||
"github.com/TheTNB/panel/internal/http/request"
|
||||
)
|
||||
|
||||
@@ -53,7 +51,7 @@ func ErrorSystem(w http.ResponseWriter) {
|
||||
render.Header(chix.HeaderContentType, chix.MIMEApplicationJSONCharsetUTF8) // must before Status()
|
||||
render.Status(http.StatusInternalServerError)
|
||||
render.JSON(&ErrorResponse{
|
||||
Message: "系统内部错误",
|
||||
Message: http.StatusText(http.StatusInternalServerError),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -64,12 +62,6 @@ func Bind[T any](r *http.Request) (*T, error) {
|
||||
// 绑定参数
|
||||
binder := chix.NewBind(r)
|
||||
defer binder.Release()
|
||||
if err := binder.URI(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := binder.Query(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if slices.Contains([]string{"POST", "PUT", "PATCH", "DELETE"}, strings.ToUpper(r.Method)) {
|
||||
if r.ContentLength > 0 {
|
||||
if err := binder.Body(req); err != nil {
|
||||
@@ -77,48 +69,58 @@ func Bind[T any](r *http.Request) (*T, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := binder.Query(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := binder.URI(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 准备验证
|
||||
df, err := validate.FromStruct(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := df.Create()
|
||||
|
||||
if reqWithPrepare, ok := any(req).(request.WithPrepare); ok {
|
||||
if err := reqWithPrepare.Prepare(r); err != nil {
|
||||
if err = reqWithPrepare.Prepare(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if reqWithAuthorize, ok := any(req).(request.WithAuthorize); ok {
|
||||
if err := reqWithAuthorize.Authorize(r); err != nil {
|
||||
if err = reqWithAuthorize.Authorize(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if reqWithRules, ok := any(req).(request.WithRules); ok {
|
||||
if rules := reqWithRules.Rules(r); rules != nil {
|
||||
app.Validator.RegisterStructValidationMapRules(rules, req)
|
||||
for key, value := range rules {
|
||||
v.StringRule(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
if reqWithFilters, ok := any(req).(request.WithFilters); ok {
|
||||
if filters := reqWithFilters.Filters(r); filters != nil {
|
||||
v.FilterRules(filters)
|
||||
}
|
||||
}
|
||||
if reqWithMessages, ok := any(req).(request.WithMessages); ok {
|
||||
if messages := reqWithMessages.Messages(r); messages != nil {
|
||||
v.AddMessages(messages)
|
||||
}
|
||||
}
|
||||
|
||||
// 验证参数
|
||||
err := app.Validator.Struct(req)
|
||||
if err == nil {
|
||||
// 开始验证
|
||||
if v.Validate() && v.IsSuccess() {
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// 翻译错误信息
|
||||
var errs validator.ValidationErrors
|
||||
if errors.As(err, &errs) {
|
||||
for _, e := range errs {
|
||||
if reqWithMessages, ok := any(req).(request.WithMessages); ok {
|
||||
if msg, found := reqWithMessages.Messages(r)[fmt.Sprintf("%s.%s", e.Field(), e.Tag())]; found {
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
}
|
||||
return nil, errors.New(e.Translate(*app.Translator)) // nolint:staticcheck
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
return nil, v.Errors.OneError()
|
||||
}
|
||||
|
||||
// Paginate 取分页条目
|
||||
func Paginate[T any](r *http.Request, allItems []T) (pagedItems []T, total uint) {
|
||||
func Paginate[T any](r *http.Request, items []T) (pagedItems []T, total uint) {
|
||||
req, err := Bind[request.Paginate](r)
|
||||
if err != nil {
|
||||
req = &request.Paginate{
|
||||
@@ -126,19 +128,19 @@ func Paginate[T any](r *http.Request, allItems []T) (pagedItems []T, total uint)
|
||||
Limit: 10,
|
||||
}
|
||||
}
|
||||
total = uint(len(allItems))
|
||||
startIndex := (req.Page - 1) * req.Limit
|
||||
endIndex := req.Page * req.Limit
|
||||
total = uint(len(items))
|
||||
start := (req.Page - 1) * req.Limit
|
||||
end := req.Page * req.Limit
|
||||
|
||||
if total == 0 {
|
||||
return []T{}, 0
|
||||
}
|
||||
if startIndex > total {
|
||||
if start > total {
|
||||
return []T{}, total
|
||||
}
|
||||
if endIndex > total {
|
||||
endIndex = total
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
|
||||
return allItems[startIndex:endIndex], total
|
||||
return items[start:end], total
|
||||
}
|
||||
Reference in New Issue
Block a user