validation.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package validation for validations
  15. //
  16. // import (
  17. // "github.com/cnlh/nps/vender/github.com/astaxie/beego/validation"
  18. // "log"
  19. // )
  20. //
  21. // type User struct {
  22. // Name string
  23. // Age int
  24. // }
  25. //
  26. // func main() {
  27. // u := User{"man", 40}
  28. // valid := validation.Validation{}
  29. // valid.Required(u.Name, "name")
  30. // valid.MaxSize(u.Name, 15, "nameMax")
  31. // valid.Range(u.Age, 0, 140, "age")
  32. // if valid.HasErrors() {
  33. // // validation does not pass
  34. // // print invalid message
  35. // for _, err := range valid.Errors {
  36. // log.Println(err.Key, err.Message)
  37. // }
  38. // }
  39. // // or use like this
  40. // if v := valid.Max(u.Age, 140, "ageMax"); !v.Ok {
  41. // log.Println(v.Error.Key, v.Error.Message)
  42. // }
  43. // }
  44. //
  45. // more info: http://beego.me/docs/mvc/controller/validation.md
  46. package validation
  47. import (
  48. "fmt"
  49. "reflect"
  50. "regexp"
  51. "strings"
  52. )
  53. // ValidFormer valid interface
  54. type ValidFormer interface {
  55. Valid(*Validation)
  56. }
  57. // Error show the error
  58. type Error struct {
  59. Message, Key, Name, Field, Tmpl string
  60. Value interface{}
  61. LimitValue interface{}
  62. }
  63. // String Returns the Message.
  64. func (e *Error) String() string {
  65. if e == nil {
  66. return ""
  67. }
  68. return e.Message
  69. }
  70. // Implement Error interface.
  71. // Return e.String()
  72. func (e *Error) Error() string { return e.String() }
  73. // Result is returned from every validation method.
  74. // It provides an indication of success, and a pointer to the Error (if any).
  75. type Result struct {
  76. Error *Error
  77. Ok bool
  78. }
  79. // Key Get Result by given key string.
  80. func (r *Result) Key(key string) *Result {
  81. if r.Error != nil {
  82. r.Error.Key = key
  83. }
  84. return r
  85. }
  86. // Message Set Result message by string or format string with args
  87. func (r *Result) Message(message string, args ...interface{}) *Result {
  88. if r.Error != nil {
  89. if len(args) == 0 {
  90. r.Error.Message = message
  91. } else {
  92. r.Error.Message = fmt.Sprintf(message, args...)
  93. }
  94. }
  95. return r
  96. }
  97. // A Validation context manages data validation and error messages.
  98. type Validation struct {
  99. // if this field set true, in struct tag valid
  100. // if the struct field vale is empty
  101. // it will skip those valid functions, see CanSkipFuncs
  102. RequiredFirst bool
  103. Errors []*Error
  104. ErrorsMap map[string][]*Error
  105. }
  106. // Clear Clean all ValidationError.
  107. func (v *Validation) Clear() {
  108. v.Errors = []*Error{}
  109. v.ErrorsMap = nil
  110. }
  111. // HasErrors Has ValidationError nor not.
  112. func (v *Validation) HasErrors() bool {
  113. return len(v.Errors) > 0
  114. }
  115. // ErrorMap Return the errors mapped by key.
  116. // If there are multiple validation errors associated with a single key, the
  117. // first one "wins". (Typically the first validation will be the more basic).
  118. func (v *Validation) ErrorMap() map[string][]*Error {
  119. return v.ErrorsMap
  120. }
  121. // Error Add an error to the validation context.
  122. func (v *Validation) Error(message string, args ...interface{}) *Result {
  123. result := (&Result{
  124. Ok: false,
  125. Error: &Error{},
  126. }).Message(message, args...)
  127. v.Errors = append(v.Errors, result.Error)
  128. return result
  129. }
  130. // Required Test that the argument is non-nil and non-empty (if string or list)
  131. func (v *Validation) Required(obj interface{}, key string) *Result {
  132. return v.apply(Required{key}, obj)
  133. }
  134. // Min Test that the obj is greater than min if obj's type is int
  135. func (v *Validation) Min(obj interface{}, min int, key string) *Result {
  136. return v.apply(Min{min, key}, obj)
  137. }
  138. // Max Test that the obj is less than max if obj's type is int
  139. func (v *Validation) Max(obj interface{}, max int, key string) *Result {
  140. return v.apply(Max{max, key}, obj)
  141. }
  142. // Range Test that the obj is between mni and max if obj's type is int
  143. func (v *Validation) Range(obj interface{}, min, max int, key string) *Result {
  144. return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, obj)
  145. }
  146. // MinSize Test that the obj is longer than min size if type is string or slice
  147. func (v *Validation) MinSize(obj interface{}, min int, key string) *Result {
  148. return v.apply(MinSize{min, key}, obj)
  149. }
  150. // MaxSize Test that the obj is shorter than max size if type is string or slice
  151. func (v *Validation) MaxSize(obj interface{}, max int, key string) *Result {
  152. return v.apply(MaxSize{max, key}, obj)
  153. }
  154. // Length Test that the obj is same length to n if type is string or slice
  155. func (v *Validation) Length(obj interface{}, n int, key string) *Result {
  156. return v.apply(Length{n, key}, obj)
  157. }
  158. // Alpha Test that the obj is [a-zA-Z] if type is string
  159. func (v *Validation) Alpha(obj interface{}, key string) *Result {
  160. return v.apply(Alpha{key}, obj)
  161. }
  162. // Numeric Test that the obj is [0-9] if type is string
  163. func (v *Validation) Numeric(obj interface{}, key string) *Result {
  164. return v.apply(Numeric{key}, obj)
  165. }
  166. // AlphaNumeric Test that the obj is [0-9a-zA-Z] if type is string
  167. func (v *Validation) AlphaNumeric(obj interface{}, key string) *Result {
  168. return v.apply(AlphaNumeric{key}, obj)
  169. }
  170. // Match Test that the obj matches regexp if type is string
  171. func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *Result {
  172. return v.apply(Match{regex, key}, obj)
  173. }
  174. // NoMatch Test that the obj doesn't match regexp if type is string
  175. func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *Result {
  176. return v.apply(NoMatch{Match{Regexp: regex}, key}, obj)
  177. }
  178. // AlphaDash Test that the obj is [0-9a-zA-Z_-] if type is string
  179. func (v *Validation) AlphaDash(obj interface{}, key string) *Result {
  180. return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, obj)
  181. }
  182. // Email Test that the obj is email address if type is string
  183. func (v *Validation) Email(obj interface{}, key string) *Result {
  184. return v.apply(Email{Match{Regexp: emailPattern}, key}, obj)
  185. }
  186. // IP Test that the obj is IP address if type is string
  187. func (v *Validation) IP(obj interface{}, key string) *Result {
  188. return v.apply(IP{Match{Regexp: ipPattern}, key}, obj)
  189. }
  190. // Base64 Test that the obj is base64 encoded if type is string
  191. func (v *Validation) Base64(obj interface{}, key string) *Result {
  192. return v.apply(Base64{Match{Regexp: base64Pattern}, key}, obj)
  193. }
  194. // Mobile Test that the obj is chinese mobile number if type is string
  195. func (v *Validation) Mobile(obj interface{}, key string) *Result {
  196. return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, obj)
  197. }
  198. // Tel Test that the obj is chinese telephone number if type is string
  199. func (v *Validation) Tel(obj interface{}, key string) *Result {
  200. return v.apply(Tel{Match{Regexp: telPattern}, key}, obj)
  201. }
  202. // Phone Test that the obj is chinese mobile or telephone number if type is string
  203. func (v *Validation) Phone(obj interface{}, key string) *Result {
  204. return v.apply(Phone{Mobile{Match: Match{Regexp: mobilePattern}},
  205. Tel{Match: Match{Regexp: telPattern}}, key}, obj)
  206. }
  207. // ZipCode Test that the obj is chinese zip code if type is string
  208. func (v *Validation) ZipCode(obj interface{}, key string) *Result {
  209. return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, obj)
  210. }
  211. func (v *Validation) apply(chk Validator, obj interface{}) *Result {
  212. if nil == obj {
  213. if chk.IsSatisfied(obj) {
  214. return &Result{Ok: true}
  215. }
  216. } else if reflect.TypeOf(obj).Kind() == reflect.Ptr {
  217. if reflect.ValueOf(obj).IsNil() {
  218. if chk.IsSatisfied(nil) {
  219. return &Result{Ok: true}
  220. }
  221. } else {
  222. if chk.IsSatisfied(reflect.ValueOf(obj).Elem().Interface()) {
  223. return &Result{Ok: true}
  224. }
  225. }
  226. } else if chk.IsSatisfied(obj) {
  227. return &Result{Ok: true}
  228. }
  229. // Add the error to the validation context.
  230. key := chk.GetKey()
  231. Name := key
  232. Field := ""
  233. parts := strings.Split(key, ".")
  234. if len(parts) == 2 {
  235. Field = parts[0]
  236. Name = parts[1]
  237. }
  238. err := &Error{
  239. Message: chk.DefaultMessage(),
  240. Key: key,
  241. Name: Name,
  242. Field: Field,
  243. Value: obj,
  244. Tmpl: MessageTmpls[Name],
  245. LimitValue: chk.GetLimitValue(),
  246. }
  247. v.setError(err)
  248. // Also return it in the result.
  249. return &Result{
  250. Ok: false,
  251. Error: err,
  252. }
  253. }
  254. // AddError adds independent error message for the provided key
  255. func (v *Validation) AddError(key, message string) {
  256. Name := key
  257. Field := ""
  258. parts := strings.Split(key, ".")
  259. if len(parts) == 2 {
  260. Field = parts[0]
  261. Name = parts[1]
  262. }
  263. err := &Error{
  264. Message: message,
  265. Key: key,
  266. Name: Name,
  267. Field: Field,
  268. }
  269. v.setError(err)
  270. }
  271. func (v *Validation) setError(err *Error) {
  272. v.Errors = append(v.Errors, err)
  273. if v.ErrorsMap == nil {
  274. v.ErrorsMap = make(map[string][]*Error)
  275. }
  276. if _, ok := v.ErrorsMap[err.Field]; !ok {
  277. v.ErrorsMap[err.Field] = []*Error{}
  278. }
  279. v.ErrorsMap[err.Field] = append(v.ErrorsMap[err.Field], err)
  280. }
  281. // SetError Set error message for one field in ValidationError
  282. func (v *Validation) SetError(fieldName string, errMsg string) *Error {
  283. err := &Error{Key: fieldName, Field: fieldName, Tmpl: errMsg, Message: errMsg}
  284. v.setError(err)
  285. return err
  286. }
  287. // Check Apply a group of validators to a field, in order, and return the
  288. // ValidationResult from the first one that fails, or the last one that
  289. // succeeds.
  290. func (v *Validation) Check(obj interface{}, checks ...Validator) *Result {
  291. var result *Result
  292. for _, check := range checks {
  293. result = v.apply(check, obj)
  294. if !result.Ok {
  295. return result
  296. }
  297. }
  298. return result
  299. }
  300. // Valid Validate a struct.
  301. // the obj parameter must be a struct or a struct pointer
  302. func (v *Validation) Valid(obj interface{}) (b bool, err error) {
  303. objT := reflect.TypeOf(obj)
  304. objV := reflect.ValueOf(obj)
  305. switch {
  306. case isStruct(objT):
  307. case isStructPtr(objT):
  308. objT = objT.Elem()
  309. objV = objV.Elem()
  310. default:
  311. err = fmt.Errorf("%v must be a struct or a struct pointer", obj)
  312. return
  313. }
  314. for i := 0; i < objT.NumField(); i++ {
  315. var vfs []ValidFunc
  316. if vfs, err = getValidFuncs(objT.Field(i)); err != nil {
  317. return
  318. }
  319. var hasRequired bool
  320. for _, vf := range vfs {
  321. if vf.Name == "Required" {
  322. hasRequired = true
  323. }
  324. currentField := objV.Field(i).Interface()
  325. if objV.Field(i).Kind() == reflect.Ptr {
  326. if objV.Field(i).IsNil() {
  327. currentField = ""
  328. } else {
  329. currentField = objV.Field(i).Elem().Interface()
  330. }
  331. }
  332. chk := Required{""}.IsSatisfied(currentField)
  333. if !hasRequired && v.RequiredFirst && !chk {
  334. if _, ok := CanSkipFuncs[vf.Name]; ok {
  335. continue
  336. }
  337. }
  338. if _, err = funcs.Call(vf.Name,
  339. mergeParam(v, objV.Field(i).Interface(), vf.Params)...); err != nil {
  340. return
  341. }
  342. }
  343. }
  344. if !v.HasErrors() {
  345. if form, ok := obj.(ValidFormer); ok {
  346. form.Valid(v)
  347. }
  348. }
  349. return !v.HasErrors(), nil
  350. }
  351. // RecursiveValid Recursively validate a struct.
  352. // Step1: Validate by v.Valid
  353. // Step2: If pass on step1, then reflect obj's fields
  354. // Step3: Do the Recursively validation to all struct or struct pointer fields
  355. func (v *Validation) RecursiveValid(objc interface{}) (bool, error) {
  356. //Step 1: validate obj itself firstly
  357. // fails if objc is not struct
  358. pass, err := v.Valid(objc)
  359. if err != nil || !pass {
  360. return pass, err // Stop recursive validation
  361. }
  362. // Step 2: Validate struct's struct fields
  363. objT := reflect.TypeOf(objc)
  364. objV := reflect.ValueOf(objc)
  365. if isStructPtr(objT) {
  366. objT = objT.Elem()
  367. objV = objV.Elem()
  368. }
  369. for i := 0; i < objT.NumField(); i++ {
  370. t := objT.Field(i).Type
  371. // Recursive applies to struct or pointer to structs fields
  372. if isStruct(t) || isStructPtr(t) {
  373. // Step 3: do the recursive validation
  374. // Only valid the Public field recursively
  375. if objV.Field(i).CanInterface() {
  376. pass, err = v.RecursiveValid(objV.Field(i).Interface())
  377. }
  378. }
  379. }
  380. return pass, err
  381. }
  382. func (v *Validation) CanSkipAlso(skipFunc string) {
  383. if _, ok := CanSkipFuncs[skipFunc]; !ok {
  384. CanSkipFuncs[skipFunc] = struct{}{}
  385. }
  386. }