engine_extended.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package validator
  2. import (
  3. "fmt"
  4. "time"
  5. "google.golang.org/protobuf/reflect/protoreflect"
  6. "google.golang.org/protobuf/types/known/durationpb"
  7. "google.golang.org/protobuf/types/known/timestamppb"
  8. validate "git.ikuban.com/server/kubanapis/kuban/api/validate"
  9. )
  10. // validateEnum 验证枚举
  11. func (e *Engine) validateEnum(
  12. vctx *ValidationContext,
  13. fieldRules *validate.FieldRules,
  14. rules *validate.EnumRules,
  15. value protoreflect.EnumNumber,
  16. field protoreflect.FieldDescriptor,
  17. fieldPath string,
  18. errors *ValidationErrors,
  19. ) error {
  20. intValue := int32(value)
  21. if rules.Const != nil && intValue != *rules.Const {
  22. defaultMsg := fmt.Sprintf("字段 %s 必须等于 %d", fieldPath, *rules.Const)
  23. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  24. e.getErrorMessage(fieldRules, vctx, "const", defaultMsg)))
  25. }
  26. // 验证是否为已定义的枚举值
  27. if rules.DefinedOnly != nil && *rules.DefinedOnly {
  28. enumValues := field.Enum().Values()
  29. found := false
  30. for i := 0; i < enumValues.Len(); i++ {
  31. if enumValues.Get(i).Number() == value {
  32. found = true
  33. break
  34. }
  35. }
  36. if !found {
  37. defaultMsg := fmt.Sprintf("字段 %s 的枚举值未定义", fieldPath)
  38. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  39. e.getErrorMessage(fieldRules, vctx, "defined_only", defaultMsg)))
  40. }
  41. }
  42. // in 验证
  43. if len(rules.In) > 0 {
  44. found := false
  45. for _, v := range rules.In {
  46. if intValue == v {
  47. found = true
  48. break
  49. }
  50. }
  51. if !found {
  52. defaultMsg := fmt.Sprintf("字段 %s 的值不在允许的列表中", fieldPath)
  53. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  54. e.getErrorMessage(fieldRules, vctx, "in", defaultMsg)))
  55. }
  56. }
  57. // not_in 验证
  58. if len(rules.NotIn) > 0 {
  59. for _, v := range rules.NotIn {
  60. if intValue == v {
  61. defaultMsg := fmt.Sprintf("字段 %s 的值在禁止列表中", fieldPath)
  62. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  63. e.getErrorMessage(fieldRules, vctx, "not_in", defaultMsg)))
  64. break
  65. }
  66. }
  67. }
  68. return nil
  69. }
  70. // validateBytes 验证字节数组
  71. func (e *Engine) validateBytes(
  72. vctx *ValidationContext,
  73. fieldRules *validate.FieldRules,
  74. rules *validate.BytesRules,
  75. value []byte,
  76. fieldPath string,
  77. errors *ValidationErrors,
  78. ) error {
  79. // const 验证
  80. if rules.Const != nil && string(value) != string(rules.Const) {
  81. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  82. fmt.Sprintf("字段 %s 必须等于指定值", fieldPath)))
  83. }
  84. // 长度验证
  85. length := uint64(len(value))
  86. if rules.Len != nil && length != *rules.Len {
  87. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidLength,
  88. fmt.Sprintf("字段 %s 长度必须为 %d 字节", fieldPath, *rules.Len)))
  89. }
  90. if rules.MinLen != nil && length < *rules.MinLen {
  91. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidLength,
  92. fmt.Sprintf("字段 %s 长度至少为 %d 字节", fieldPath, *rules.MinLen)))
  93. }
  94. if rules.MaxLen != nil && length > *rules.MaxLen {
  95. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidLength,
  96. fmt.Sprintf("字段 %s 长度最多为 %d 字节", fieldPath, *rules.MaxLen)))
  97. }
  98. // TODO: pattern, prefix, suffix, contains 验证
  99. // in 验证
  100. if len(rules.In) > 0 {
  101. found := false
  102. for _, allowed := range rules.In {
  103. if string(value) == string(allowed) {
  104. found = true
  105. break
  106. }
  107. }
  108. if !found {
  109. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  110. fmt.Sprintf("字段 %s 的值不在允许的列表中", fieldPath)))
  111. }
  112. }
  113. // not_in 验证
  114. if len(rules.NotIn) > 0 {
  115. for _, disallowed := range rules.NotIn {
  116. if string(value) == string(disallowed) {
  117. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  118. fmt.Sprintf("字段 %s 的值在禁止列表中", fieldPath)))
  119. break
  120. }
  121. }
  122. }
  123. return nil
  124. }
  125. // validateDuration 验证 Duration
  126. func (e *Engine) validateDuration(
  127. vctx *ValidationContext,
  128. rules *validate.DurationRules,
  129. value *durationpb.Duration,
  130. fieldPath string,
  131. errors *ValidationErrors,
  132. ) error {
  133. if value == nil {
  134. if rules.Required != nil && *rules.Required {
  135. errors.Add(NewValidationError(fieldPath, ErrCodeRequired,
  136. fmt.Sprintf("字段 %s 是必填的", fieldPath)))
  137. }
  138. return nil
  139. }
  140. seconds := value.Seconds
  141. // const 验证
  142. if rules.ConstSeconds != nil && seconds != *rules.ConstSeconds {
  143. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  144. fmt.Sprintf("字段 %s 必须等于 %d 秒", fieldPath, *rules.ConstSeconds)))
  145. }
  146. // 范围验证
  147. if rules.LtSeconds != nil && seconds >= *rules.LtSeconds {
  148. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  149. fmt.Sprintf("字段 %s 必须小于 %d 秒", fieldPath, *rules.LtSeconds)))
  150. }
  151. if rules.LteSeconds != nil && seconds > *rules.LteSeconds {
  152. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  153. fmt.Sprintf("字段 %s 必须小于等于 %d 秒", fieldPath, *rules.LteSeconds)))
  154. }
  155. if rules.GtSeconds != nil && seconds <= *rules.GtSeconds {
  156. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  157. fmt.Sprintf("字段 %s 必须大于 %d 秒", fieldPath, *rules.GtSeconds)))
  158. }
  159. if rules.GteSeconds != nil && seconds < *rules.GteSeconds {
  160. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  161. fmt.Sprintf("字段 %s 必须大于等于 %d 秒", fieldPath, *rules.GteSeconds)))
  162. }
  163. return nil
  164. }
  165. // validateTimestamp 验证 Timestamp
  166. func (e *Engine) validateTimestamp(
  167. vctx *ValidationContext,
  168. rules *validate.TimestampRules,
  169. value *timestamppb.Timestamp,
  170. fieldPath string,
  171. errors *ValidationErrors,
  172. ) error {
  173. if value == nil {
  174. if rules.Required != nil && *rules.Required {
  175. errors.Add(NewValidationError(fieldPath, ErrCodeRequired,
  176. fmt.Sprintf("字段 %s 是必填的", fieldPath)))
  177. }
  178. return nil
  179. }
  180. timestamp := value.Seconds
  181. // const 验证
  182. if rules.Const != nil && timestamp != *rules.Const {
  183. errors.Add(NewValidationError(fieldPath, ErrCodeInvalidValue,
  184. fmt.Sprintf("字段 %s 必须等于指定时间", fieldPath)))
  185. }
  186. // 范围验证
  187. if rules.Lt != nil && timestamp >= *rules.Lt {
  188. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  189. fmt.Sprintf("字段 %s 必须早于指定时间", fieldPath)))
  190. }
  191. if rules.Lte != nil && timestamp > *rules.Lte {
  192. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  193. fmt.Sprintf("字段 %s 必须早于或等于指定时间", fieldPath)))
  194. }
  195. if rules.Gt != nil && timestamp <= *rules.Gt {
  196. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  197. fmt.Sprintf("字段 %s 必须晚于指定时间", fieldPath)))
  198. }
  199. if rules.Gte != nil && timestamp < *rules.Gte {
  200. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  201. fmt.Sprintf("字段 %s 必须晚于或等于指定时间", fieldPath)))
  202. }
  203. // 相对时间验证
  204. now := time.Now().Unix()
  205. if rules.LtNow != nil && *rules.LtNow && timestamp >= now {
  206. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  207. fmt.Sprintf("字段 %s 必须在当前时间之前", fieldPath)))
  208. }
  209. if rules.GtNow != nil && *rules.GtNow && timestamp <= now {
  210. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  211. fmt.Sprintf("字段 %s 必须在当前时间之后", fieldPath)))
  212. }
  213. // 时间范围验证
  214. if rules.WithinSeconds != nil {
  215. diff := timestamp - now
  216. if diff < 0 {
  217. diff = -diff
  218. }
  219. if diff > *rules.WithinSeconds {
  220. errors.Add(NewValidationError(fieldPath, ErrCodeOutOfRange,
  221. fmt.Sprintf("字段 %s 必须在当前时间的 %d 秒内", fieldPath, *rules.WithinSeconds)))
  222. }
  223. }
  224. return nil
  225. }