1
0

validation.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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/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. Errors []*Error
  100. ErrorsMap map[string]*Error
  101. }
  102. // Clear Clean all ValidationError.
  103. func (v *Validation) Clear() {
  104. v.Errors = []*Error{}
  105. v.ErrorsMap = nil
  106. }
  107. // HasErrors Has ValidationError nor not.
  108. func (v *Validation) HasErrors() bool {
  109. return len(v.Errors) > 0
  110. }
  111. // ErrorMap Return the errors mapped by key.
  112. // If there are multiple validation errors associated with a single key, the
  113. // first one "wins". (Typically the first validation will be the more basic).
  114. func (v *Validation) ErrorMap() map[string]*Error {
  115. return v.ErrorsMap
  116. }
  117. // Error Add an error to the validation context.
  118. func (v *Validation) Error(message string, args ...interface{}) *Result {
  119. result := (&Result{
  120. Ok: false,
  121. Error: &Error{},
  122. }).Message(message, args...)
  123. v.Errors = append(v.Errors, result.Error)
  124. return result
  125. }
  126. // Required Test that the argument is non-nil and non-empty (if string or list)
  127. func (v *Validation) Required(obj interface{}, key string) *Result {
  128. return v.apply(Required{key}, obj)
  129. }
  130. // Min Test that the obj is greater than min if obj's type is int
  131. func (v *Validation) Min(obj interface{}, min int, key string) *Result {
  132. return v.apply(Min{min, key}, obj)
  133. }
  134. // Max Test that the obj is less than max if obj's type is int
  135. func (v *Validation) Max(obj interface{}, max int, key string) *Result {
  136. return v.apply(Max{max, key}, obj)
  137. }
  138. // Range Test that the obj is between mni and max if obj's type is int
  139. func (v *Validation) Range(obj interface{}, min, max int, key string) *Result {
  140. return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, obj)
  141. }
  142. // MinSize Test that the obj is longer than min size if type is string or slice
  143. func (v *Validation) MinSize(obj interface{}, min int, key string) *Result {
  144. return v.apply(MinSize{min, key}, obj)
  145. }
  146. // MaxSize Test that the obj is shorter than max size if type is string or slice
  147. func (v *Validation) MaxSize(obj interface{}, max int, key string) *Result {
  148. return v.apply(MaxSize{max, key}, obj)
  149. }
  150. // Length Test that the obj is same length to n if type is string or slice
  151. func (v *Validation) Length(obj interface{}, n int, key string) *Result {
  152. return v.apply(Length{n, key}, obj)
  153. }
  154. // Alpha Test that the obj is [a-zA-Z] if type is string
  155. func (v *Validation) Alpha(obj interface{}, key string) *Result {
  156. return v.apply(Alpha{key}, obj)
  157. }
  158. // Numeric Test that the obj is [0-9] if type is string
  159. func (v *Validation) Numeric(obj interface{}, key string) *Result {
  160. return v.apply(Numeric{key}, obj)
  161. }
  162. // AlphaNumeric Test that the obj is [0-9a-zA-Z] if type is string
  163. func (v *Validation) AlphaNumeric(obj interface{}, key string) *Result {
  164. return v.apply(AlphaNumeric{key}, obj)
  165. }
  166. // Match Test that the obj matches regexp if type is string
  167. func (v *Validation) Match(obj interface{}, regex *regexp.Regexp, key string) *Result {
  168. return v.apply(Match{regex, key}, obj)
  169. }
  170. // NoMatch Test that the obj doesn't match regexp if type is string
  171. func (v *Validation) NoMatch(obj interface{}, regex *regexp.Regexp, key string) *Result {
  172. return v.apply(NoMatch{Match{Regexp: regex}, key}, obj)
  173. }
  174. // AlphaDash Test that the obj is [0-9a-zA-Z_-] if type is string
  175. func (v *Validation) AlphaDash(obj interface{}, key string) *Result {
  176. return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, obj)
  177. }
  178. // Email Test that the obj is email address if type is string
  179. func (v *Validation) Email(obj interface{}, key string) *Result {
  180. return v.apply(Email{Match{Regexp: emailPattern}, key}, obj)
  181. }
  182. // IP Test that the obj is IP address if type is string
  183. func (v *Validation) IP(obj interface{}, key string) *Result {
  184. return v.apply(IP{Match{Regexp: ipPattern}, key}, obj)
  185. }
  186. // Base64 Test that the obj is base64 encoded if type is string
  187. func (v *Validation) Base64(obj interface{}, key string) *Result {
  188. return v.apply(Base64{Match{Regexp: base64Pattern}, key}, obj)
  189. }
  190. // Mobile Test that the obj is chinese mobile number if type is string
  191. func (v *Validation) Mobile(obj interface{}, key string) *Result {
  192. return v.apply(Mobile{Match{Regexp: mobilePattern}, key}, obj)
  193. }
  194. // Tel Test that the obj is chinese telephone number if type is string
  195. func (v *Validation) Tel(obj interface{}, key string) *Result {
  196. return v.apply(Tel{Match{Regexp: telPattern}, key}, obj)
  197. }
  198. // Phone Test that the obj is chinese mobile or telephone number if type is string
  199. func (v *Validation) Phone(obj interface{}, key string) *Result {
  200. return v.apply(Phone{Mobile{Match: Match{Regexp: mobilePattern}},
  201. Tel{Match: Match{Regexp: telPattern}}, key}, obj)
  202. }
  203. // ZipCode Test that the obj is chinese zip code if type is string
  204. func (v *Validation) ZipCode(obj interface{}, key string) *Result {
  205. return v.apply(ZipCode{Match{Regexp: zipCodePattern}, key}, obj)
  206. }
  207. func (v *Validation) apply(chk Validator, obj interface{}) *Result {
  208. if chk.IsSatisfied(obj) {
  209. return &Result{Ok: true}
  210. }
  211. // Add the error to the validation context.
  212. key := chk.GetKey()
  213. Name := key
  214. Field := ""
  215. parts := strings.Split(key, ".")
  216. if len(parts) == 2 {
  217. Field = parts[0]
  218. Name = parts[1]
  219. }
  220. err := &Error{
  221. Message: chk.DefaultMessage(),
  222. Key: key,
  223. Name: Name,
  224. Field: Field,
  225. Value: obj,
  226. Tmpl: MessageTmpls[Name],
  227. LimitValue: chk.GetLimitValue(),
  228. }
  229. v.setError(err)
  230. // Also return it in the result.
  231. return &Result{
  232. Ok: false,
  233. Error: err,
  234. }
  235. }
  236. func (v *Validation) setError(err *Error) {
  237. v.Errors = append(v.Errors, err)
  238. if v.ErrorsMap == nil {
  239. v.ErrorsMap = make(map[string]*Error)
  240. }
  241. if _, ok := v.ErrorsMap[err.Field]; !ok {
  242. v.ErrorsMap[err.Field] = err
  243. }
  244. }
  245. // SetError Set error message for one field in ValidationError
  246. func (v *Validation) SetError(fieldName string, errMsg string) *Error {
  247. err := &Error{Key: fieldName, Field: fieldName, Tmpl: errMsg, Message: errMsg}
  248. v.setError(err)
  249. return err
  250. }
  251. // Check Apply a group of validators to a field, in order, and return the
  252. // ValidationResult from the first one that fails, or the last one that
  253. // succeeds.
  254. func (v *Validation) Check(obj interface{}, checks ...Validator) *Result {
  255. var result *Result
  256. for _, check := range checks {
  257. result = v.apply(check, obj)
  258. if !result.Ok {
  259. return result
  260. }
  261. }
  262. return result
  263. }
  264. // Valid Validate a struct.
  265. // the obj parameter must be a struct or a struct pointer
  266. func (v *Validation) Valid(obj interface{}) (b bool, err error) {
  267. objT := reflect.TypeOf(obj)
  268. objV := reflect.ValueOf(obj)
  269. switch {
  270. case isStruct(objT):
  271. case isStructPtr(objT):
  272. objT = objT.Elem()
  273. objV = objV.Elem()
  274. default:
  275. err = fmt.Errorf("%v must be a struct or a struct pointer", obj)
  276. return
  277. }
  278. for i := 0; i < objT.NumField(); i++ {
  279. var vfs []ValidFunc
  280. if vfs, err = getValidFuncs(objT.Field(i)); err != nil {
  281. return
  282. }
  283. for _, vf := range vfs {
  284. if _, err = funcs.Call(vf.Name,
  285. mergeParam(v, objV.Field(i).Interface(), vf.Params)...); err != nil {
  286. return
  287. }
  288. }
  289. }
  290. if !v.HasErrors() {
  291. if form, ok := obj.(ValidFormer); ok {
  292. form.Valid(v)
  293. }
  294. }
  295. return !v.HasErrors(), nil
  296. }
  297. // RecursiveValid Recursively validate a struct.
  298. // Step1: Validate by v.Valid
  299. // Step2: If pass on step1, then reflect obj's fields
  300. // Step3: Do the Recursively validation to all struct or struct pointer fields
  301. func (v *Validation) RecursiveValid(objc interface{}) (bool, error) {
  302. //Step 1: validate obj itself firstly
  303. // fails if objc is not struct
  304. pass, err := v.Valid(objc)
  305. if err != nil || false == pass {
  306. return pass, err // Stop recursive validation
  307. }
  308. // Step 2: Validate struct's struct fields
  309. objT := reflect.TypeOf(objc)
  310. objV := reflect.ValueOf(objc)
  311. if isStructPtr(objT) {
  312. objT = objT.Elem()
  313. objV = objV.Elem()
  314. }
  315. for i := 0; i < objT.NumField(); i++ {
  316. t := objT.Field(i).Type
  317. // Recursive applies to struct or pointer to structs fields
  318. if isStruct(t) || isStructPtr(t) {
  319. // Step 3: do the recursive validation
  320. // Only valid the Public field recursively
  321. if objV.Field(i).CanInterface() {
  322. pass, err = v.RecursiveValid(objV.Field(i).Interface())
  323. }
  324. }
  325. }
  326. return pass, err
  327. }