| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- package validator
- import (
- "fmt"
- "time"
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/types/known/durationpb"
- "google.golang.org/protobuf/types/known/timestamppb"
- validate "git.ikuban.com/server/kubanapis/kuban/api/validate"
- )
- // validateEnum 验证枚举
- func (e *Engine) validateEnum(
- vctx *ValidationContext,
- fieldRules *validate.FieldRules,
- rules *validate.EnumRules,
- value protoreflect.EnumNumber,
- field protoreflect.FieldDescriptor,
- fieldPath string,
- errors *ValidationErrors,
- ) error {
- intValue := int32(value)
- if rules.Const != nil && intValue != *rules.Const {
- defaultMsg := fmt.Sprintf("字段 %s 必须等于 %d", fieldPath, *rules.Const)
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- e.getErrorMessage(fieldRules, vctx, "const", defaultMsg)))
- }
- // 验证是否为已定义的枚举值
- if rules.DefinedOnly != nil && *rules.DefinedOnly {
- enumValues := field.Enum().Values()
- found := false
- for i := 0; i < enumValues.Len(); i++ {
- if enumValues.Get(i).Number() == value {
- found = true
- break
- }
- }
- if !found {
- defaultMsg := fmt.Sprintf("字段 %s 的枚举值未定义", fieldPath)
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- e.getErrorMessage(fieldRules, vctx, "defined_only", defaultMsg)))
- }
- }
- // in 验证
- if len(rules.In) > 0 {
- found := false
- for _, v := range rules.In {
- if intValue == v {
- found = true
- break
- }
- }
- if !found {
- defaultMsg := fmt.Sprintf("字段 %s 的值不在允许的列表中", fieldPath)
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- e.getErrorMessage(fieldRules, vctx, "in", defaultMsg)))
- }
- }
- // not_in 验证
- if len(rules.NotIn) > 0 {
- for _, v := range rules.NotIn {
- if intValue == v {
- defaultMsg := fmt.Sprintf("字段 %s 的值在禁止列表中", fieldPath)
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- e.getErrorMessage(fieldRules, vctx, "not_in", defaultMsg)))
- break
- }
- }
- }
- return nil
- }
- // validateBytes 验证字节数组
- func (e *Engine) validateBytes(
- vctx *ValidationContext,
- fieldRules *validate.FieldRules,
- rules *validate.BytesRules,
- value []byte,
- fieldPath string,
- errors *ValidationErrors,
- ) error {
- // const 验证
- if rules.Const != nil && string(value) != string(rules.Const) {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- fmt.Sprintf("字段 %s 必须等于指定值", fieldPath)))
- }
- // 长度验证
- length := uint64(len(value))
- if rules.Len != nil && length != *rules.Len {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidLength,
- fmt.Sprintf("字段 %s 长度必须为 %d 字节", fieldPath, *rules.Len)))
- }
- if rules.MinLen != nil && length < *rules.MinLen {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidLength,
- fmt.Sprintf("字段 %s 长度至少为 %d 字节", fieldPath, *rules.MinLen)))
- }
- if rules.MaxLen != nil && length > *rules.MaxLen {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidLength,
- fmt.Sprintf("字段 %s 长度最多为 %d 字节", fieldPath, *rules.MaxLen)))
- }
- // TODO: pattern, prefix, suffix, contains 验证
- // in 验证
- if len(rules.In) > 0 {
- found := false
- for _, allowed := range rules.In {
- if string(value) == string(allowed) {
- found = true
- break
- }
- }
- if !found {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- fmt.Sprintf("字段 %s 的值不在允许的列表中", fieldPath)))
- }
- }
- // not_in 验证
- if len(rules.NotIn) > 0 {
- for _, disallowed := range rules.NotIn {
- if string(value) == string(disallowed) {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- fmt.Sprintf("字段 %s 的值在禁止列表中", fieldPath)))
- break
- }
- }
- }
- return nil
- }
- // validateDuration 验证 Duration
- func (e *Engine) validateDuration(
- vctx *ValidationContext,
- rules *validate.DurationRules,
- value *durationpb.Duration,
- fieldPath string,
- errors *ValidationErrors,
- ) error {
- if value == nil {
- if rules.Required != nil && *rules.Required {
- errors.Add(NewValidationError(fieldPath, ErrCodeRequired,
- fmt.Sprintf("字段 %s 是必填的", fieldPath)))
- }
- return nil
- }
- seconds := value.Seconds
- // const 验证
- if rules.ConstSeconds != nil && seconds != *rules.ConstSeconds {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- fmt.Sprintf("字段 %s 必须等于 %d 秒", fieldPath, *rules.ConstSeconds)))
- }
- // 范围验证
- if rules.LtSeconds != nil && seconds >= *rules.LtSeconds {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须小于 %d 秒", fieldPath, *rules.LtSeconds)))
- }
- if rules.LteSeconds != nil && seconds > *rules.LteSeconds {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须小于等于 %d 秒", fieldPath, *rules.LteSeconds)))
- }
- if rules.GtSeconds != nil && seconds <= *rules.GtSeconds {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须大于 %d 秒", fieldPath, *rules.GtSeconds)))
- }
- if rules.GteSeconds != nil && seconds < *rules.GteSeconds {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须大于等于 %d 秒", fieldPath, *rules.GteSeconds)))
- }
- return nil
- }
- // validateTimestamp 验证 Timestamp
- func (e *Engine) validateTimestamp(
- vctx *ValidationContext,
- rules *validate.TimestampRules,
- value *timestamppb.Timestamp,
- fieldPath string,
- errors *ValidationErrors,
- ) error {
- if value == nil {
- if rules.Required != nil && *rules.Required {
- errors.Add(NewValidationError(fieldPath, ErrCodeRequired,
- fmt.Sprintf("字段 %s 是必填的", fieldPath)))
- }
- return nil
- }
- timestamp := value.Seconds
- // const 验证
- if rules.Const != nil && timestamp != *rules.Const {
- errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
- fmt.Sprintf("字段 %s 必须等于指定时间", fieldPath)))
- }
- // 范围验证
- if rules.Lt != nil && timestamp >= *rules.Lt {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须早于指定时间", fieldPath)))
- }
- if rules.Lte != nil && timestamp > *rules.Lte {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须早于或等于指定时间", fieldPath)))
- }
- if rules.Gt != nil && timestamp <= *rules.Gt {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须晚于指定时间", fieldPath)))
- }
- if rules.Gte != nil && timestamp < *rules.Gte {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须晚于或等于指定时间", fieldPath)))
- }
- // 相对时间验证
- now := time.Now().Unix()
- if rules.LtNow != nil && *rules.LtNow && timestamp >= now {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须在当前时间之前", fieldPath)))
- }
- if rules.GtNow != nil && *rules.GtNow && timestamp <= now {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须在当前时间之后", fieldPath)))
- }
- // 时间范围验证
- if rules.WithinSeconds != nil {
- diff := timestamp - now
- if diff < 0 {
- diff = -diff
- }
- if diff > *rules.WithinSeconds {
- errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
- fmt.Sprintf("字段 %s 必须在当前时间的 %d 秒内", fieldPath, *rules.WithinSeconds)))
- }
- }
- return nil
- }
|