/util/govalidator/field_validator.go

https://github.com/goodrain/rainbond · Go · 552 lines · 471 code · 39 blank · 42 comment · 150 complexity · 2112df8271f48f4e744aa5f275fa71b1 MD5 · raw file

  1. package validator
  2. import (
  3. "fmt"
  4. "net/url"
  5. "strconv"
  6. "strings"
  7. )
  8. type fieldValidator struct {
  9. field string
  10. value string
  11. rule string
  12. message string
  13. errsBag url.Values
  14. }
  15. // rmMap contains all the pre defined rules and their associate methods
  16. var rmMap = map[string]string{
  17. "required": "Required",
  18. "regex": "Regex",
  19. "alpha": "Alpha",
  20. "alpha_dash": "AlphaDash",
  21. "alpha_num": "AlphaNumeric",
  22. "bool": "Boolean",
  23. "between": "Between",
  24. "credit_card": "CreditCard",
  25. "coordinate": "Coordinate",
  26. "css_color": "ValidateCSSColor",
  27. "digits": "Digits",
  28. "digits_between": "DigitsBetween",
  29. "date": "Date",
  30. "email": "Email",
  31. "float": "ValidateFloat",
  32. "in": "In",
  33. "ip": "IP",
  34. "ip_v4": "IPv4",
  35. "ip_v6": "IPv6",
  36. "not_in": "NotIn",
  37. "json": "ValidateJSON",
  38. "len": "Length",
  39. "lat": "Latitude",
  40. "lon": "Longitude",
  41. "min": "Min",
  42. "max": "Max",
  43. "numeric": "Numeric",
  44. "numeric_between": "NumericBetween",
  45. "url": "ValidateURL",
  46. "uuid": "UUID",
  47. "uuid_v3": "UUID3",
  48. "uuid_v4": "UUID4",
  49. "uuid_v5": "UUID5",
  50. }
  51. //run perform all the available field validation against a field and rule
  52. func (v *fieldValidator) run() {
  53. v.field = strings.TrimSpace(v.field) //remove space form field
  54. v.rule = strings.TrimSpace(v.rule) //remove space form rule
  55. rule := v.rule
  56. if strings.Contains(rule, ":") {
  57. rule = strings.Split(v.rule, ":")[0]
  58. }
  59. if r, ok := rmMap[rule]; ok {
  60. callMethodByName(v, r)
  61. }
  62. }
  63. // Required check the Required fields
  64. func (v *fieldValidator) Required() {
  65. if v.value != "" {
  66. return
  67. }
  68. if v.message != "" {
  69. v.errsBag.Add(v.field, v.message)
  70. return
  71. }
  72. v.errsBag.Add(v.field, fmt.Sprintf("The %s field is required", v.field))
  73. }
  74. // Regex check the custom Regex rules
  75. // Regex:^[a-zA-Z]+$ means this field can only contain alphabet (a-z and A-Z)
  76. func (v *fieldValidator) Regex() {
  77. rxStr := strings.TrimPrefix(v.rule, "regex:")
  78. if IsMatchedRegex(rxStr, v.value) {
  79. return
  80. }
  81. if v.message != "" {
  82. v.errsBag.Add(v.field, v.message)
  83. return
  84. }
  85. v.errsBag.Add(v.field, fmt.Sprintf("The %s field format is invalid", v.field))
  86. }
  87. // Alpha check if provided field contains valid letters
  88. func (v *fieldValidator) Alpha() {
  89. if IsAlpha(v.value) {
  90. return
  91. }
  92. if v.message != "" {
  93. v.errsBag.Add(v.field, v.message)
  94. return
  95. }
  96. v.errsBag.Add(v.field, fmt.Sprintf("The %s may only contain letters", v.field))
  97. }
  98. // AlphaDash check if provided field contains valid letters, numbers, underscore and dash
  99. func (v *fieldValidator) AlphaDash() {
  100. if IsAlphaDash(v.value) {
  101. return
  102. }
  103. if v.message != "" {
  104. v.errsBag.Add(v.field, v.message)
  105. return
  106. }
  107. v.errsBag.Add(v.field, fmt.Sprintf("The %s may only contain letters, numbers, and dashes", v.field))
  108. }
  109. // AlphaNumeric check if provided field contains valid letters and numbers
  110. func (v *fieldValidator) AlphaNumeric() {
  111. if IsAlphaNumeric(v.value) {
  112. return
  113. }
  114. if v.message != "" {
  115. v.errsBag.Add(v.field, v.message)
  116. return
  117. }
  118. v.errsBag.Add(v.field, fmt.Sprintf("The %s may only contain letters and numbers", v.field))
  119. }
  120. // Boolean check if provided field contains Boolean
  121. // in this case: "0", "1", 0, 1, "true", "false", true, false etc
  122. func (v *fieldValidator) Boolean() {
  123. if IsBoolean(v.value) {
  124. return
  125. }
  126. if v.message != "" {
  127. v.errsBag.Add(v.field, v.message)
  128. return
  129. }
  130. v.errsBag.Add(v.field, fmt.Sprintf("The %s may only contain 0, 1, true, false", v.field))
  131. }
  132. // CreditCard check if provided field contains valid credit card number
  133. // Accepted cards are Visa, MasterCard, American Express, Diners Club, Discover and JCB card
  134. func (v *fieldValidator) CreditCard() {
  135. if IsCreditCard(v.value) {
  136. return
  137. }
  138. if v.message != "" {
  139. v.errsBag.Add(v.field, v.message)
  140. return
  141. }
  142. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid credit card number", v.field))
  143. }
  144. // Coordinate check if provided field contains valid Coordinate
  145. func (v *fieldValidator) Coordinate() {
  146. if IsCoordinate(v.value) {
  147. return
  148. }
  149. if v.message != "" {
  150. v.errsBag.Add(v.field, v.message)
  151. return
  152. }
  153. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid coordinate", v.field))
  154. }
  155. // ValidateCSSColor check if provided field contains a valid CSS color code
  156. func (v *fieldValidator) ValidateCSSColor() {
  157. if IsCSSColor(v.value) {
  158. return
  159. }
  160. if v.message != "" {
  161. v.errsBag.Add(v.field, v.message)
  162. return
  163. }
  164. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid CSS color code", v.field))
  165. }
  166. // ValidateJSON check if provided field contains valid json string
  167. func (v *fieldValidator) ValidateJSON() {
  168. if IsJSON(v.value) {
  169. return
  170. }
  171. if v.message != "" {
  172. v.errsBag.Add(v.field, v.message)
  173. return
  174. }
  175. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain valid JSON string", v.field))
  176. }
  177. // Length check the field's character Length
  178. func (v *fieldValidator) Length() {
  179. l, err := strconv.Atoi(strings.TrimPrefix(v.rule, "len:"))
  180. if err != nil {
  181. panic(errStringToInt)
  182. }
  183. if len(v.value) == l {
  184. return
  185. }
  186. if v.message != "" {
  187. v.errsBag.Add(v.field, v.message)
  188. return
  189. }
  190. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be %d characters", v.field, l))
  191. }
  192. // Min check the field's minimum character length
  193. func (v *fieldValidator) Min() {
  194. l, err := strconv.Atoi(strings.TrimPrefix(v.rule, "min:"))
  195. if err != nil {
  196. panic(errStringToInt)
  197. }
  198. if l <= len(v.value) {
  199. return
  200. }
  201. if v.message != "" {
  202. v.errsBag.Add(v.field, v.message)
  203. return
  204. }
  205. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be minimum %d characters", v.field, l))
  206. }
  207. // Max check the field's maximum character length
  208. func (v *fieldValidator) Max() {
  209. l, err := strconv.Atoi(strings.TrimPrefix(v.rule, "max:"))
  210. if err != nil {
  211. panic(errStringToInt)
  212. }
  213. if l >= len(v.value) {
  214. return
  215. }
  216. if v.message != "" {
  217. v.errsBag.Add(v.field, v.message)
  218. return
  219. }
  220. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be maximum %d characters", v.field, l))
  221. }
  222. // Between check the fields character length range
  223. func (v *fieldValidator) Between() {
  224. rng := strings.Split(strings.TrimPrefix(v.rule, "between:"), ",")
  225. if len(rng) != 2 {
  226. panic(errInvalidArgument)
  227. }
  228. min, err := strconv.Atoi(rng[0])
  229. if err != nil {
  230. panic(errStringToInt)
  231. }
  232. max, err := strconv.Atoi(rng[1])
  233. if err != nil {
  234. panic(errStringToInt)
  235. }
  236. if len(v.value) >= min && len(v.value) <= max {
  237. return
  238. }
  239. if v.message != "" {
  240. v.errsBag.Add(v.field, v.message)
  241. return
  242. }
  243. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be between %d and %d", v.field, min, max))
  244. }
  245. // Numeric check if the value of the field is Numeric
  246. func (v *fieldValidator) Numeric() {
  247. if IsNumeric(v.value) {
  248. return
  249. }
  250. if v.message != "" {
  251. v.errsBag.Add(v.field, v.message)
  252. return
  253. }
  254. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be numeric", v.field))
  255. }
  256. // NumericBetween check if the value field numeric value range
  257. // e.g: numeric_between:18, 65 means number value must be in between a numeric value 18 & 65
  258. func (v *fieldValidator) NumericBetween() {
  259. rng := strings.Split(strings.TrimPrefix(v.rule, "numeric_between:"), ",")
  260. if len(rng) != 2 {
  261. panic(errInvalidArgument)
  262. }
  263. min, err := strconv.Atoi(rng[0])
  264. if err != nil {
  265. panic(errStringToInt)
  266. }
  267. max, err := strconv.Atoi(rng[1])
  268. if err != nil {
  269. panic(errStringToInt)
  270. }
  271. digit, err := strconv.Atoi(v.value)
  272. if err != nil {
  273. if v.message != "" {
  274. v.errsBag.Add(v.field, v.message)
  275. return
  276. }
  277. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be numeric value between %d and %d", v.field, min, max))
  278. return
  279. }
  280. if digit >= min && digit <= max {
  281. return
  282. }
  283. if v.message != "" {
  284. v.errsBag.Add(v.field, v.message)
  285. return
  286. }
  287. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be numeric value between %d and %d", v.field, min, max))
  288. }
  289. // Digits check the exact matching length of digit (0,9)
  290. // Digits:5 means the field must have 5 digit of length.
  291. // e.g: 12345 or 98997 etc
  292. func (v *fieldValidator) Digits() {
  293. l, err := strconv.Atoi(strings.TrimPrefix(v.rule, "digits:"))
  294. if err != nil {
  295. panic(errStringToInt)
  296. }
  297. if len(v.value) == l && IsNumeric(v.value) {
  298. return
  299. }
  300. if !IsNumeric(v.value) || len(v.value) != l {
  301. if v.message != "" {
  302. v.errsBag.Add(v.field, v.message)
  303. return
  304. }
  305. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be %d digits", v.field, l))
  306. }
  307. }
  308. // DigitsBetween check if the field contains only digit and length between provided range
  309. // e.g: digits_between:4,5 means the field can have value like: 8887 or 12345 etc
  310. func (v *fieldValidator) DigitsBetween() {
  311. rng := strings.Split(strings.TrimPrefix(v.rule, "digits_between:"), ",")
  312. if len(rng) != 2 {
  313. panic(errInvalidArgument)
  314. }
  315. min, err := strconv.Atoi(rng[0])
  316. if err != nil {
  317. panic(errStringToInt)
  318. }
  319. max, err := strconv.Atoi(rng[1])
  320. if err != nil {
  321. panic(errStringToInt)
  322. }
  323. if (len(v.value) >= min && len(v.value) <= max) && IsNumeric(v.value) {
  324. return
  325. }
  326. if !IsNumeric(v.value) || !(len(v.value) >= min && len(v.value) <= max) {
  327. if v.message != "" {
  328. v.errsBag.Add(v.field, v.message)
  329. return
  330. }
  331. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be digits between %d and %d", v.field, min, max))
  332. }
  333. }
  334. // Email check the provided field is valid Email
  335. func (v *fieldValidator) Email() {
  336. if IsEmail(v.value) {
  337. return
  338. }
  339. if v.message != "" {
  340. v.errsBag.Add(v.field, v.message)
  341. return
  342. }
  343. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid email address", v.field))
  344. }
  345. // Date check the provided field is valid Date
  346. func (v *fieldValidator) Date() {
  347. if v.rule == "date:dd-mm-yyyy" {
  348. if IsDateDDMMYY(v.value) {
  349. return
  350. }
  351. if v.message != "" {
  352. v.errsBag.Add(v.field, v.message)
  353. return
  354. }
  355. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid date format. e.g: dd-mm-yyyy, dd/mm/yyyy etc", v.field))
  356. return
  357. }
  358. if IsDate(v.value) {
  359. return
  360. }
  361. if v.message != "" {
  362. v.errsBag.Add(v.field, v.message)
  363. return
  364. }
  365. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid date format. e.g: yyyy-mm-dd, yyyy/mm/dd etc.", v.field))
  366. }
  367. // validFloat check the provided field is valid float number
  368. func (v *fieldValidator) ValidateFloat() {
  369. if IsFloat(v.value) {
  370. return
  371. }
  372. if v.message != "" {
  373. v.errsBag.Add(v.field, v.message)
  374. return
  375. }
  376. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a float number", v.field))
  377. }
  378. // Latitude check if provided field contains valid Latitude
  379. func (v *fieldValidator) Latitude() {
  380. if IsLatitude(v.value) {
  381. return
  382. }
  383. if v.message != "" {
  384. v.errsBag.Add(v.field, v.message)
  385. return
  386. }
  387. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain valid latitude", v.field))
  388. }
  389. // Longitude check if provided field contains valid Longitude
  390. func (v *fieldValidator) Longitude() {
  391. if IsLongitude(v.value) {
  392. return
  393. }
  394. if v.message != "" {
  395. v.errsBag.Add(v.field, v.message)
  396. return
  397. }
  398. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain valid longitude", v.field))
  399. }
  400. // In check if provided field's value exist In the provided rules
  401. func (v *fieldValidator) In() {
  402. params := strings.TrimPrefix(v.rule, "in:")
  403. haystack := strings.Split(params, ",")
  404. if IsIn(haystack, v.value) {
  405. return
  406. }
  407. if v.message != "" {
  408. v.errsBag.Add(v.field, v.message)
  409. return
  410. }
  411. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain one of these values %s", v.field, params))
  412. }
  413. // NotIn check if provided field's value exist in the provided rules
  414. func (v *fieldValidator) NotIn() {
  415. params := strings.TrimPrefix(v.rule, "not_in:")
  416. haystack := strings.Split(params, ",")
  417. if !IsIn(haystack, v.value) {
  418. return
  419. }
  420. if v.message != "" {
  421. v.errsBag.Add(v.field, v.message)
  422. return
  423. }
  424. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain values except %s", v.field, params))
  425. }
  426. // IP check if provided field is valid IP address
  427. func (v *fieldValidator) IP() {
  428. if IsIP(v.value) {
  429. return
  430. }
  431. if v.message != "" {
  432. v.errsBag.Add(v.field, v.message)
  433. return
  434. }
  435. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid IP address", v.field))
  436. }
  437. // IPv4 check if provided field is valid IP address of version 4
  438. func (v *fieldValidator) IPv4() {
  439. if IsIPV4(v.value) {
  440. return
  441. }
  442. if v.message != "" {
  443. v.errsBag.Add(v.field, v.message)
  444. return
  445. }
  446. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid IPV4 address", v.field))
  447. }
  448. // IPv6 check if provided field is valid IP address of version 6
  449. func (v *fieldValidator) IPv6() {
  450. if IsIPV6(v.value) {
  451. return
  452. }
  453. if v.message != "" {
  454. v.errsBag.Add(v.field, v.message)
  455. return
  456. }
  457. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must be a valid IPV6 address", v.field))
  458. }
  459. // ValidateURL check if provided field is valid URL
  460. func (v *fieldValidator) ValidateURL() {
  461. if IsURL(v.value) {
  462. return
  463. }
  464. if v.message != "" {
  465. v.errsBag.Add(v.field, v.message)
  466. return
  467. }
  468. v.errsBag.Add(v.field, fmt.Sprintf("The %s field format is invalid", v.field))
  469. }
  470. // UUID check if provided field contains valid UUID
  471. func (v *fieldValidator) UUID() {
  472. if IsUUID(v.value) {
  473. return
  474. }
  475. if v.message != "" {
  476. v.errsBag.Add(v.field, v.message)
  477. return
  478. }
  479. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain valid UUID", v.field))
  480. }
  481. // UUID3 check if provided field contains valid UUID of version 3
  482. func (v *fieldValidator) UUID3() {
  483. if IsUUID3(v.value) {
  484. return
  485. }
  486. if v.message != "" {
  487. v.errsBag.Add(v.field, v.message)
  488. return
  489. }
  490. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain valid UUID V3", v.field))
  491. }
  492. // UUID4 check if provided field contains valid UUID of version 4
  493. func (v *fieldValidator) UUID4() {
  494. if IsUUID4(v.value) {
  495. return
  496. }
  497. if v.message != "" {
  498. v.errsBag.Add(v.field, v.message)
  499. return
  500. }
  501. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain valid UUID V4", v.field))
  502. }
  503. // UUID5 check if provided field contains valid UUID of version 5
  504. func (v *fieldValidator) UUID5() {
  505. if IsUUID5(v.value) {
  506. return
  507. }
  508. if v.message != "" {
  509. v.errsBag.Add(v.field, v.message)
  510. return
  511. }
  512. v.errsBag.Add(v.field, fmt.Sprintf("The %s field must contain valid UUID V5", v.field))
  513. }