6d05163c by miraclesu

add validation funcs

1 parent a41cd170
1 package validation
2
3 import (
4 "fmt"
5 "regexp"
6 )
7
8 type ValidationError struct {
9 Message, Key string
10 }
11
12 // Returns the Message.
13 func (e *ValidationError) String() string {
14 if e == nil {
15 return ""
16 }
17 return e.Message
18 }
19
20 // A Validation context manages data validation and error messages.
21 type Validation struct {
22 Errors []*ValidationError
23 }
24
25 func (v *Validation) Clear() {
26 v.Errors = []*ValidationError{}
27 }
28
29 func (v *Validation) HasErrors() bool {
30 return len(v.Errors) > 0
31 }
32
33 // Return the errors mapped by key.
34 // If there are multiple validation errors associated with a single key, the
35 // first one "wins". (Typically the first validation will be the more basic).
36 func (v *Validation) ErrorMap() map[string]*ValidationError {
37 m := map[string]*ValidationError{}
38 for _, e := range v.Errors {
39 if _, ok := m[e.Key]; !ok {
40 m[e.Key] = e
41 }
42 }
43 return m
44 }
45
46 // Add an error to the validation context.
47 func (v *Validation) Error(message string, args ...interface{}) *ValidationResult {
48 result := (&ValidationResult{
49 Ok: false,
50 Error: &ValidationError{},
51 }).Message(message, args...)
52 v.Errors = append(v.Errors, result.Error)
53 return result
54 }
55
56 // A ValidationResult is returned from every validation method.
57 // It provides an indication of success, and a pointer to the Error (if any).
58 type ValidationResult struct {
59 Error *ValidationError
60 Ok bool
61 }
62
63 func (r *ValidationResult) Key(key string) *ValidationResult {
64 if r.Error != nil {
65 r.Error.Key = key
66 }
67 return r
68 }
69
70 func (r *ValidationResult) Message(message string, args ...interface{}) *ValidationResult {
71 if r.Error != nil {
72 if len(args) == 0 {
73 r.Error.Message = message
74 } else {
75 r.Error.Message = fmt.Sprintf(message, args)
76 }
77 }
78 return r
79 }
80
81 // Test that the argument is non-nil and non-empty (if string or list)
82 func (v *Validation) Required(obj interface{}, key string) *ValidationResult {
83 return v.apply(Required{key}, obj)
84 }
85
86 func (v *Validation) Min(n int, min int, key string) *ValidationResult {
87 return v.apply(Min{min, key}, n)
88 }
89
90 func (v *Validation) Max(n int, max int, key string) *ValidationResult {
91 return v.apply(Max{max, key}, n)
92 }
93
94 func (v *Validation) Range(n, min, max int, key string) *ValidationResult {
95 return v.apply(Range{Min{Min: min}, Max{Max: max}, key}, n)
96 }
97
98 func (v *Validation) MinSize(obj interface{}, min int, key string) *ValidationResult {
99 return v.apply(MinSize{min, key}, obj)
100 }
101
102 func (v *Validation) MaxSize(obj interface{}, max int, key string) *ValidationResult {
103 return v.apply(MaxSize{max, key}, obj)
104 }
105
106 func (v *Validation) Length(obj interface{}, n int, key string) *ValidationResult {
107 return v.apply(Length{n, key}, obj)
108 }
109
110 func (v *Validation) Alpha(obj interface{}, n int, key string) *ValidationResult {
111 return v.apply(Alpha{key}, obj)
112 }
113
114 func (v *Validation) Numeric(obj interface{}, n int, key string) *ValidationResult {
115 return v.apply(Numeric{key}, obj)
116 }
117
118 func (v *Validation) AlphaNumeric(obj interface{}, n int, key string) *ValidationResult {
119 return v.apply(AlphaNumeric{key}, obj)
120 }
121
122 func (v *Validation) Match(str string, regex *regexp.Regexp, key string) *ValidationResult {
123 return v.apply(Match{regex, key}, str)
124 }
125
126 func (v *Validation) NoMatch(str string, regex *regexp.Regexp, key string) *ValidationResult {
127 return v.apply(NoMatch{Match{Regexp: regex}, key}, str)
128 }
129
130 func (v *Validation) AlphaDash(str string, key string) *ValidationResult {
131 return v.apply(AlphaDash{NoMatch{Match: Match{Regexp: alphaDashPattern}}, key}, str)
132 }
133
134 func (v *Validation) Email(str string, key string) *ValidationResult {
135 return v.apply(Email{Match{Regexp: emailPattern}, key}, str)
136 }
137
138 func (v *Validation) IP(str string, key string) *ValidationResult {
139 return v.apply(IP{Match{Regexp: ipPattern}, key}, str)
140 }
141
142 func (v *Validation) Base64(str string, key string) *ValidationResult {
143 return v.apply(Base64{Match{Regexp: base64Pattern}, key}, str)
144 }
145
146 func (v *Validation) apply(chk Validator, obj interface{}) *ValidationResult {
147 if chk.IsSatisfied(obj) {
148 return &ValidationResult{Ok: true}
149 }
150
151 // Add the error to the validation context.
152 err := &ValidationError{
153 Message: chk.DefaultMessage(),
154 Key: chk.GetKey(),
155 }
156 v.Errors = append(v.Errors, err)
157
158 // Also return it in the result.
159 return &ValidationResult{
160 Ok: false,
161 Error: err,
162 }
163 }
164
165 // Apply a group of validators to a field, in order, and return the
166 // ValidationResult from the first one that fails, or the last one that
167 // succeeds.
168 func (v *Validation) Check(obj interface{}, checks ...Validator) *ValidationResult {
169 var result *ValidationResult
170 for _, check := range checks {
171 result = v.apply(check, obj)
172 if !result.Ok {
173 return result
174 }
175 }
176 return result
177 }
1 package revel 1 package validation
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
...@@ -10,9 +10,12 @@ import ( ...@@ -10,9 +10,12 @@ import (
10 type Validator interface { 10 type Validator interface {
11 IsSatisfied(interface{}) bool 11 IsSatisfied(interface{}) bool
12 DefaultMessage() string 12 DefaultMessage() string
13 GetKey() string
13 } 14 }
14 15
15 type Required struct{} 16 type Required struct {
17 Key string
18 }
16 19
17 func (r Required) IsSatisfied(obj interface{}) bool { 20 func (r Required) IsSatisfied(obj interface{}) bool {
18 if obj == nil { 21 if obj == nil {
...@@ -42,11 +45,13 @@ func (r Required) DefaultMessage() string { ...@@ -42,11 +45,13 @@ func (r Required) DefaultMessage() string {
42 return "Required" 45 return "Required"
43 } 46 }
44 47
45 // TODO 48 func (r Required) GetKey() string {
46 // type Unique struct {} 49 return r.Key
50 }
47 51
48 type Min struct { 52 type Min struct {
49 Min int 53 Min int
54 Key string
50 } 55 }
51 56
52 func (m Min) IsSatisfied(obj interface{}) bool { 57 func (m Min) IsSatisfied(obj interface{}) bool {
...@@ -61,8 +66,13 @@ func (m Min) DefaultMessage() string { ...@@ -61,8 +66,13 @@ func (m Min) DefaultMessage() string {
61 return fmt.Sprintln("Minimum is", m.Min) 66 return fmt.Sprintln("Minimum is", m.Min)
62 } 67 }
63 68
69 func (m Min) GetKey() string {
70 return m.Key
71 }
72
64 type Max struct { 73 type Max struct {
65 Max int 74 Max int
75 Key string
66 } 76 }
67 77
68 func (m Max) IsSatisfied(obj interface{}) bool { 78 func (m Max) IsSatisfied(obj interface{}) bool {
...@@ -77,10 +87,15 @@ func (m Max) DefaultMessage() string { ...@@ -77,10 +87,15 @@ func (m Max) DefaultMessage() string {
77 return fmt.Sprintln("Maximum is", m.Max) 87 return fmt.Sprintln("Maximum is", m.Max)
78 } 88 }
79 89
90 func (m Max) GetKey() string {
91 return m.Key
92 }
93
80 // Requires an integer to be within Min, Max inclusive. 94 // Requires an integer to be within Min, Max inclusive.
81 type Range struct { 95 type Range struct {
82 Min 96 Min
83 Max 97 Max
98 Key string
84 } 99 }
85 100
86 func (r Range) IsSatisfied(obj interface{}) bool { 101 func (r Range) IsSatisfied(obj interface{}) bool {
...@@ -91,9 +106,14 @@ func (r Range) DefaultMessage() string { ...@@ -91,9 +106,14 @@ func (r Range) DefaultMessage() string {
91 return fmt.Sprintln("Range is", r.Min.Min, "to", r.Max.Max) 106 return fmt.Sprintln("Range is", r.Min.Min, "to", r.Max.Max)
92 } 107 }
93 108
109 func (r Range) GetKey() string {
110 return r.Key
111 }
112
94 // Requires an array or string to be at least a given length. 113 // Requires an array or string to be at least a given length.
95 type MinSize struct { 114 type MinSize struct {
96 Min int 115 Min int
116 Key string
97 } 117 }
98 118
99 func (m MinSize) IsSatisfied(obj interface{}) bool { 119 func (m MinSize) IsSatisfied(obj interface{}) bool {
...@@ -111,9 +131,14 @@ func (m MinSize) DefaultMessage() string { ...@@ -111,9 +131,14 @@ func (m MinSize) DefaultMessage() string {
111 return fmt.Sprintln("Minimum size is", m.Min) 131 return fmt.Sprintln("Minimum size is", m.Min)
112 } 132 }
113 133
134 func (m MinSize) GetKey() string {
135 return m.Key
136 }
137
114 // Requires an array or string to be at most a given length. 138 // Requires an array or string to be at most a given length.
115 type MaxSize struct { 139 type MaxSize struct {
116 Max int 140 Max int
141 Key string
117 } 142 }
118 143
119 func (m MaxSize) IsSatisfied(obj interface{}) bool { 144 func (m MaxSize) IsSatisfied(obj interface{}) bool {
...@@ -131,27 +156,38 @@ func (m MaxSize) DefaultMessage() string { ...@@ -131,27 +156,38 @@ func (m MaxSize) DefaultMessage() string {
131 return fmt.Sprintln("Maximum size is", m.Max) 156 return fmt.Sprintln("Maximum size is", m.Max)
132 } 157 }
133 158
159 func (m MaxSize) GetKey() string {
160 return m.Key
161 }
162
134 // Requires an array or string to be exactly a given length. 163 // Requires an array or string to be exactly a given length.
135 type Length struct { 164 type Length struct {
136 N int 165 N int
166 Key string
137 } 167 }
138 168
139 func (s Length) IsSatisfied(obj interface{}) bool { 169 func (l Length) IsSatisfied(obj interface{}) bool {
140 if str, ok := obj.(string); ok { 170 if str, ok := obj.(string); ok {
141 return len(str) == s.N 171 return len(str) == l.N
142 } 172 }
143 v := reflect.ValueOf(obj) 173 v := reflect.ValueOf(obj)
144 if v.Kind() == reflect.Slice { 174 if v.Kind() == reflect.Slice {
145 return v.Len() == s.N 175 return v.Len() == l.N
146 } 176 }
147 return false 177 return false
148 } 178 }
149 179
150 func (s Length) DefaultMessage() string { 180 func (l Length) DefaultMessage() string {
151 return fmt.Sprintln("Required length is", s.N) 181 return fmt.Sprintln("Required length is", l.N)
152 } 182 }
153 183
154 type Alpha struct{} 184 func (l Length) GetKey() string {
185 return l.Key
186 }
187
188 type Alpha struct {
189 Key string
190 }
155 191
156 func (a Alpha) IsSatisfied(obj interface{}) bool { 192 func (a Alpha) IsSatisfied(obj interface{}) bool {
157 if str, ok := obj.(string); ok { 193 if str, ok := obj.(string); ok {
...@@ -168,7 +204,13 @@ func (a Alpha) DefaultMessage() string { ...@@ -168,7 +204,13 @@ func (a Alpha) DefaultMessage() string {
168 return fmt.Sprintln("Must be valid alpha characters") 204 return fmt.Sprintln("Must be valid alpha characters")
169 } 205 }
170 206
171 type Numeric struct{} 207 func (a Alpha) GetKey() string {
208 return a.Key
209 }
210
211 type Numeric struct {
212 Key string
213 }
172 214
173 func (n Numeric) IsSatisfied(obj interface{}) bool { 215 func (n Numeric) IsSatisfied(obj interface{}) bool {
174 if str, ok := obj.(string); ok { 216 if str, ok := obj.(string); ok {
...@@ -185,7 +227,13 @@ func (n Numeric) DefaultMessage() string { ...@@ -185,7 +227,13 @@ func (n Numeric) DefaultMessage() string {
185 return fmt.Sprintln("Must be valid numeric characters") 227 return fmt.Sprintln("Must be valid numeric characters")
186 } 228 }
187 229
188 type AlphaNumeric struct{} 230 func (n Numeric) GetKey() string {
231 return n.Key
232 }
233
234 type AlphaNumeric struct {
235 Key string
236 }
189 237
190 func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { 238 func (a AlphaNumeric) IsSatisfied(obj interface{}) bool {
191 if str, ok := obj.(string); ok { 239 if str, ok := obj.(string); ok {
...@@ -202,9 +250,14 @@ func (a AlphaNumeric) DefaultMessage() string { ...@@ -202,9 +250,14 @@ func (a AlphaNumeric) DefaultMessage() string {
202 return fmt.Sprintln("Must be valid alpha or numeric characters") 250 return fmt.Sprintln("Must be valid alpha or numeric characters")
203 } 251 }
204 252
253 func (a AlphaNumeric) GetKey() string {
254 return a.Key
255 }
256
205 // Requires a string to match a given regex. 257 // Requires a string to match a given regex.
206 type Match struct { 258 type Match struct {
207 Regexp *regexp.Regexp 259 Regexp *regexp.Regexp
260 Key string
208 } 261 }
209 262
210 func (m Match) IsSatisfied(obj interface{}) bool { 263 func (m Match) IsSatisfied(obj interface{}) bool {
...@@ -216,55 +269,84 @@ func (m Match) DefaultMessage() string { ...@@ -216,55 +269,84 @@ func (m Match) DefaultMessage() string {
216 return fmt.Sprintln("Must match", m.Regexp) 269 return fmt.Sprintln("Must match", m.Regexp)
217 } 270 }
218 271
272 func (m Match) GetKey() string {
273 return m.Key
274 }
275
219 // Requires a string to not match a given regex. 276 // Requires a string to not match a given regex.
220 type NoMatch struct { 277 type NoMatch struct {
221 Match 278 Match
279 Key string
280 }
281
282 func (n NoMatch) IsSatisfied(obj interface{}) bool {
283 return !n.Match.IsSatisfied(obj)
222 } 284 }
223 285
224 func (m NoMatch) IsSatisfied(obj interface{}) bool { 286 func (n NoMatch) DefaultMessage() string {
225 return !m.Match.IsSatisfied(obj) 287 return fmt.Sprintln("Must no match", n.Regexp)
226 } 288 }
227 289
228 func (m NoMatch) DefaultMessage() string { 290 func (n NoMatch) GetKey() string {
229 return fmt.Sprintln("Must no match", m.Regexp) 291 return n.Key
230 } 292 }
231 293
232 var alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]") 294 var alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]")
233 295
234 type AlphaDash struct { 296 type AlphaDash struct {
235 NoMatch 297 NoMatch
298 Key string
236 } 299 }
237 300
238 func (a AlphaDash) DefaultMessage() string { 301 func (a AlphaDash) DefaultMessage() string {
239 return fmt.Sprintln("Must be valid characters") 302 return fmt.Sprintln("Must be valid characters")
240 } 303 }
241 304
305 func (a AlphaDash) GetKey() string {
306 return a.Key
307 }
308
242 var emailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?") 309 var emailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?")
243 310
244 type Email struct { 311 type Email struct {
245 Match 312 Match
313 Key string
246 } 314 }
247 315
248 func (e Email) DefaultMessage() string { 316 func (e Email) DefaultMessage() string {
249 return fmt.Sprintln("Must be a valid email address") 317 return fmt.Sprintln("Must be a valid email address")
250 } 318 }
251 319
320 func (e Email) GetKey() string {
321 return e.Key
322 }
323
252 var ipPattern = regexp.MustCompile("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)") 324 var ipPattern = regexp.MustCompile("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)")
253 325
254 type IP struct { 326 type IP struct {
255 Match 327 Match
328 Key string
256 } 329 }
257 330
258 func (i IP) DefaultMessage() string { 331 func (i IP) DefaultMessage() string {
259 return fmt.Sprintln("Must be a valid ip address") 332 return fmt.Sprintln("Must be a valid ip address")
260 } 333 }
261 334
335 func (i IP) GetKey() string {
336 return i.Key
337 }
338
262 var base64Pattern = regexp.MustCompile("^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$") 339 var base64Pattern = regexp.MustCompile("^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")
263 340
264 type Base64 struct { 341 type Base64 struct {
265 Match 342 Match
343 Key string
266 } 344 }
267 345
268 func (b Base64) DefaultMessage() string { 346 func (b Base64) DefaultMessage() string {
269 return fmt.Sprintln("Must be valid base64 characters") 347 return fmt.Sprintln("Must be valid base64 characters")
270 } 348 }
349
350 func (b Base64) GetKey() string {
351 return b.Key
352 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!