2022-09-27 17:59:05 +08:00
|
|
|
package validator
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"reflect"
|
|
|
|
|
|
|
|
"github.com/go-playground/locales"
|
|
|
|
english "github.com/go-playground/locales/en"
|
|
|
|
zhongwen "github.com/go-playground/locales/zh"
|
|
|
|
"github.com/go-playground/universal-translator"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
|
|
"github.com/go-playground/validator/v10/translations/en"
|
|
|
|
"github.com/go-playground/validator/v10/translations/zh"
|
2022-10-14 17:01:06 +08:00
|
|
|
"github.com/segmentfault/answer/internal/base/reason"
|
2022-09-27 17:59:05 +08:00
|
|
|
"github.com/segmentfault/answer/internal/base/translator"
|
2022-10-14 17:01:06 +08:00
|
|
|
myErrors "github.com/segmentfault/pacman/errors"
|
2022-09-27 17:59:05 +08:00
|
|
|
"github.com/segmentfault/pacman/i18n"
|
2022-10-20 16:38:56 +08:00
|
|
|
"github.com/segmentfault/pacman/log"
|
2022-09-27 17:59:05 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// MyValidator my validator
|
|
|
|
type MyValidator struct {
|
|
|
|
Validate *validator.Validate
|
|
|
|
Tran ut.Translator
|
|
|
|
Lang i18n.Language
|
|
|
|
}
|
|
|
|
|
|
|
|
// ErrorField error field
|
|
|
|
type ErrorField struct {
|
|
|
|
Key string `json:"key"`
|
|
|
|
Value string `json:"value"`
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
// GlobalValidatorMapping is a mapping from validator to translator used
|
|
|
|
GlobalValidatorMapping = make(map[string]*MyValidator, 0)
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
zhTran, zhVal := getTran(zhongwen.New(), i18n.LanguageChinese.Abbr()), createDefaultValidator(i18n.LanguageChinese)
|
|
|
|
if err := zh.RegisterDefaultTranslations(zhVal, zhTran); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
GlobalValidatorMapping[i18n.LanguageChinese.Abbr()] = &MyValidator{Validate: zhVal, Tran: zhTran, Lang: i18n.LanguageChinese}
|
|
|
|
|
|
|
|
enTran, enVal := getTran(english.New(), i18n.LanguageEnglish.Abbr()), createDefaultValidator(i18n.LanguageEnglish)
|
|
|
|
if err := en.RegisterDefaultTranslations(enVal, enTran); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
GlobalValidatorMapping[i18n.LanguageEnglish.Abbr()] = &MyValidator{Validate: enVal, Tran: enTran, Lang: i18n.LanguageEnglish}
|
|
|
|
}
|
|
|
|
|
|
|
|
func getTran(lo locales.Translator, la string) ut.Translator {
|
|
|
|
tran, ok := ut.New(lo, lo).GetTranslator(la)
|
|
|
|
if !ok {
|
|
|
|
panic(ok)
|
|
|
|
}
|
|
|
|
return tran
|
|
|
|
}
|
|
|
|
|
|
|
|
func createDefaultValidator(la i18n.Language) *validator.Validate {
|
|
|
|
validate := validator.New()
|
|
|
|
validate.RegisterTagNameFunc(func(fld reflect.StructField) (res string) {
|
|
|
|
defer func() {
|
|
|
|
if len(res) > 0 {
|
|
|
|
res = translator.GlobalTrans.Tr(la, res)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
if jsonTag := fld.Tag.Get("json"); len(jsonTag) > 0 {
|
|
|
|
if jsonTag == "-" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return jsonTag
|
|
|
|
}
|
|
|
|
if formTag := fld.Tag.Get("form"); len(formTag) > 0 {
|
|
|
|
return formTag
|
|
|
|
}
|
|
|
|
return fld.Name
|
|
|
|
})
|
|
|
|
return validate
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetValidatorByLang(la string) *MyValidator {
|
|
|
|
if GlobalValidatorMapping[la] != nil {
|
|
|
|
return GlobalValidatorMapping[la]
|
|
|
|
}
|
|
|
|
return GlobalValidatorMapping[i18n.DefaultLang.Abbr()]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check /
|
|
|
|
func (m *MyValidator) Check(value interface{}) (errField *ErrorField, err error) {
|
|
|
|
err = m.Validate.Struct(value)
|
|
|
|
if err != nil {
|
|
|
|
var valErrors validator.ValidationErrors
|
|
|
|
if !errors.As(err, &valErrors) {
|
2022-10-20 16:38:56 +08:00
|
|
|
log.Error(err)
|
2022-09-27 17:59:05 +08:00
|
|
|
return nil, errors.New("validate check exception")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, fieldError := range valErrors {
|
|
|
|
errField = &ErrorField{
|
|
|
|
Key: translator.GlobalTrans.Tr(m.Lang, fieldError.Field()),
|
|
|
|
Value: fieldError.Translate(m.Tran),
|
|
|
|
}
|
2022-10-14 17:01:06 +08:00
|
|
|
return errField, myErrors.BadRequest(reason.RequestFormatError).WithMsg(fieldError.Translate(m.Tran))
|
2022-09-27 17:59:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if v, ok := value.(Checker); ok {
|
|
|
|
errField, err = v.Check()
|
|
|
|
if err != nil {
|
|
|
|
return errField, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Checker .
|
|
|
|
type Checker interface {
|
|
|
|
Check() (errField *ErrorField, err error)
|
|
|
|
}
|