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 }