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