a41cd170 by miraclesu

add validators

1 parent ec7324e9
1 package revel
2
3 import (
4 "fmt"
5 "reflect"
6 "regexp"
7 "time"
8 )
9
10 type Validator interface {
11 IsSatisfied(interface{}) bool
12 DefaultMessage() string
13 }
14
15 type Required struct{}
16
17 func (r Required) IsSatisfied(obj interface{}) bool {
18 if obj == nil {
19 return false
20 }
21
22 if str, ok := obj.(string); ok {
23 return len(str) > 0
24 }
25 if b, ok := obj.(bool); ok {
26 return b
27 }
28 if i, ok := obj.(int); ok {
29 return i != 0
30 }
31 if t, ok := obj.(time.Time); ok {
32 return !t.IsZero()
33 }
34 v := reflect.ValueOf(obj)
35 if v.Kind() == reflect.Slice {
36 return v.Len() > 0
37 }
38 return true
39 }
40
41 func (r Required) DefaultMessage() string {
42 return "Required"
43 }
44
45 // TODO
46 // type Unique struct {}
47
48 type Min struct {
49 Min int
50 }
51
52 func (m Min) IsSatisfied(obj interface{}) bool {
53 num, ok := obj.(int)
54 if ok {
55 return num >= m.Min
56 }
57 return false
58 }
59
60 func (m Min) DefaultMessage() string {
61 return fmt.Sprintln("Minimum is", m.Min)
62 }
63
64 type Max struct {
65 Max int
66 }
67
68 func (m Max) IsSatisfied(obj interface{}) bool {
69 num, ok := obj.(int)
70 if ok {
71 return num <= m.Max
72 }
73 return false
74 }
75
76 func (m Max) DefaultMessage() string {
77 return fmt.Sprintln("Maximum is", m.Max)
78 }
79
80 // Requires an integer to be within Min, Max inclusive.
81 type Range struct {
82 Min
83 Max
84 }
85
86 func (r Range) IsSatisfied(obj interface{}) bool {
87 return r.Min.IsSatisfied(obj) && r.Max.IsSatisfied(obj)
88 }
89
90 func (r Range) DefaultMessage() string {
91 return fmt.Sprintln("Range is", r.Min.Min, "to", r.Max.Max)
92 }
93
94 // Requires an array or string to be at least a given length.
95 type MinSize struct {
96 Min int
97 }
98
99 func (m MinSize) IsSatisfied(obj interface{}) bool {
100 if str, ok := obj.(string); ok {
101 return len(str) >= m.Min
102 }
103 v := reflect.ValueOf(obj)
104 if v.Kind() == reflect.Slice {
105 return v.Len() >= m.Min
106 }
107 return false
108 }
109
110 func (m MinSize) DefaultMessage() string {
111 return fmt.Sprintln("Minimum size is", m.Min)
112 }
113
114 // Requires an array or string to be at most a given length.
115 type MaxSize struct {
116 Max int
117 }
118
119 func (m MaxSize) IsSatisfied(obj interface{}) bool {
120 if str, ok := obj.(string); ok {
121 return len(str) <= m.Max
122 }
123 v := reflect.ValueOf(obj)
124 if v.Kind() == reflect.Slice {
125 return v.Len() <= m.Max
126 }
127 return false
128 }
129
130 func (m MaxSize) DefaultMessage() string {
131 return fmt.Sprintln("Maximum size is", m.Max)
132 }
133
134 // Requires an array or string to be exactly a given length.
135 type Length struct {
136 N int
137 }
138
139 func (s Length) IsSatisfied(obj interface{}) bool {
140 if str, ok := obj.(string); ok {
141 return len(str) == s.N
142 }
143 v := reflect.ValueOf(obj)
144 if v.Kind() == reflect.Slice {
145 return v.Len() == s.N
146 }
147 return false
148 }
149
150 func (s Length) DefaultMessage() string {
151 return fmt.Sprintln("Required length is", s.N)
152 }
153
154 type Alpha struct{}
155
156 func (a Alpha) IsSatisfied(obj interface{}) bool {
157 if str, ok := obj.(string); ok {
158 for _, v := range str {
159 if ('Z' < v || v < 'A') && ('z' < v || v < 'a') {
160 return false
161 }
162 }
163 }
164 return false
165 }
166
167 func (a Alpha) DefaultMessage() string {
168 return fmt.Sprintln("Must be valid alpha characters")
169 }
170
171 type Numeric struct{}
172
173 func (n Numeric) IsSatisfied(obj interface{}) bool {
174 if str, ok := obj.(string); ok {
175 for _, v := range str {
176 if '9' < v || v < '0' {
177 return false
178 }
179 }
180 }
181 return false
182 }
183
184 func (n Numeric) DefaultMessage() string {
185 return fmt.Sprintln("Must be valid numeric characters")
186 }
187
188 type AlphaNumeric struct{}
189
190 func (a AlphaNumeric) IsSatisfied(obj interface{}) bool {
191 if str, ok := obj.(string); ok {
192 for _, v := range str {
193 if ('Z' < v || v < 'A') && ('z' < v || v < 'a') && ('9' < v || v < '0') {
194 return false
195 }
196 }
197 }
198 return false
199 }
200
201 func (a AlphaNumeric) DefaultMessage() string {
202 return fmt.Sprintln("Must be valid alpha or numeric characters")
203 }
204
205 // Requires a string to match a given regex.
206 type Match struct {
207 Regexp *regexp.Regexp
208 }
209
210 func (m Match) IsSatisfied(obj interface{}) bool {
211 str := obj.(string)
212 return m.Regexp.MatchString(str)
213 }
214
215 func (m Match) DefaultMessage() string {
216 return fmt.Sprintln("Must match", m.Regexp)
217 }
218
219 // Requires a string to not match a given regex.
220 type NoMatch struct {
221 Match
222 }
223
224 func (m NoMatch) IsSatisfied(obj interface{}) bool {
225 return !m.Match.IsSatisfied(obj)
226 }
227
228 func (m NoMatch) DefaultMessage() string {
229 return fmt.Sprintln("Must no match", m.Regexp)
230 }
231
232 var alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]")
233
234 type AlphaDash struct {
235 NoMatch
236 }
237
238 func (a AlphaDash) DefaultMessage() string {
239 return fmt.Sprintln("Must be valid characters")
240 }
241
242 var emailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?")
243
244 type Email struct {
245 Match
246 }
247
248 func (e Email) DefaultMessage() string {
249 return fmt.Sprintln("Must be a valid email address")
250 }
251
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?)")
253
254 type IP struct {
255 Match
256 }
257
258 func (i IP) DefaultMessage() string {
259 return fmt.Sprintln("Must be a valid ip address")
260 }
261
262 var base64Pattern = regexp.MustCompile("^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$")
263
264 type Base64 struct {
265 Match
266 }
267
268 func (b Base64) DefaultMessage() string {
269 return fmt.Sprintln("Must be valid base64 characters")
270 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!