1
// Copyright 2019 Aporeto Inc.
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at
5
//     http://www.apache.org/licenses/LICENSE-2.0
6
// Unless required by applicable law or agreed to in writing, software
7
// distributed under the License is distributed on an "AS IS" BASIS,
8
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
// See the License for the specific language governing permissions and
10
// limitations under the License.
11

12
// Author: Alexandre Wilhelm
13
// See LICENSE file for full LICENSE
14
// Copyright 2016 Aporeto.
15

16
package elemental
17

18
import (
19
	"fmt"
20
	"net/http"
21
	"reflect"
22
	"regexp"
23
	"time"
24
)
25

26
const (
27
	maximumIntFailFormat             = `Data '%d' of attribute '%s' should be less than %d`
28
	maximumIntExclusiveFailFormat    = `Data '%d' of attribute '%s' should be less or equal than %d`
29
	minimumIntFailFormat             = `Data '%d' of attribute '%s' should be greater than %d`
30
	minimumIntExclusiveFailFormat    = `Data '%d' of attribute '%s' should be greater or equal than %d`
31
	maximumFloatFailFormat           = `Data '%g' of attribute '%s' should be less than %g`
32
	maximumFloatExclusiveFailFormat  = `Data '%g' of attribute '%s' should be less or equal than %g`
33
	minimumFloatFailFormat           = `Data '%g' of attribute '%s' should be greater than %g`
34
	minimumFloatExclusiveFailFormat  = `Data '%g' of attribute '%s' should be greater or equal than %g`
35
	maximumLengthFailFormat          = `Data '%s' of attribute '%s' should be less than %d chars long`
36
	maximumLengthExclusiveFailFormat = `Data '%s' of attribute '%s' should be less or equal than %d chars long`
37
	minimumLengthFailFormat          = `Data '%s' of attribute '%s' should be greater than %d chars long`
38
	minimumLengthExclusiveFailFormat = `Data '%s' of attribute '%s' should be greater or equal than %d chars long`
39
	patternFailFormat                = `Data '%s' of attribute '%s' %s`
40
	requiredFloatFailFormat          = `Attribute '%s' is required`
41
	requiredStringFailFormat         = `Attribute '%s' is required`
42
	requiredTimeFailFormat           = `Attribute '%s' is required`
43
	requiredIntFailFormat            = `Attribute '%s' is required`
44
	requiredExternalFailFormat       = `Attribute '%s' is required`
45
	floatInListFormat                = `Data '%g' of attribute '%s' is not in list '%g'`
46
	stringInListFormat               = `Data '%s' of attribute '%s' is not in list '%s'`
47
	stringInMap                      = `Data '%s' of attribute '%s' is not in map '%s'`
48
	floatInMap                       = `Data '%g' of attribute '%s' is not in map '%g'`
49
	intInMap                         = `Data '%d' of attribute '%s' is not in map '%d'`
50
	intInListFormat                  = `Data '%d' of attribute '%s' is not in list '%d'`
51
)
52

53
// A Validatable is the interface for objects that can be validated.
54
type Validatable interface {
55
	Validate() error
56
}
57

58
// ValidateStringInList validates if the string is in the list.
59
func ValidateStringInList(attribute string, value string, enums []string, autogenerated bool) error {
60

61 14
	if autogenerated && value == "" {
62 14
		return nil
63
	}
64

65
	for _, v := range enums {
66 14
		if v == value {
67 14
			return nil
68
		}
69
	}
70

71 14
	err := NewError("Validation Error", fmt.Sprintf(stringInListFormat, value, attribute, enums), "elemental", http.StatusUnprocessableEntity)
72 14
	err.Data = map[string]string{"attribute": attribute}
73 14
	return err
74
}
75

76
// ValidateStringInMap validates if the string is in the list.
77
func ValidateStringInMap(attribute string, value string, enums map[string]interface{}, autogenerated bool) error {
78

79 14
	if autogenerated && value == "" {
80 14
		return nil
81
	}
82

83 14
	if _, ok := enums[value]; ok {
84 14
		return nil
85
	}
86

87 14
	err := NewError("Validation Error", fmt.Sprintf(stringInMap, value, attribute, enums), "elemental", http.StatusUnprocessableEntity)
88 14
	err.Data = map[string]string{"attribute": attribute}
89 14
	return err
90
}
91

92
// ValidateFloatInMap validates if the string is in the list.
93
func ValidateFloatInMap(attribute string, value float64, enums map[float64]interface{}) error {
94

95 14
	if _, ok := enums[value]; ok {
96 14
		return nil
97
	}
98

99 14
	err := NewError("Validation Error", fmt.Sprintf(floatInMap, value, attribute, enums), "elemental", http.StatusUnprocessableEntity)
100 14
	err.Data = map[string]string{"attribute": attribute}
101 14
	return err
102
}
103

104
// ValidateIntInMap validates if the string is in the list.
105
func ValidateIntInMap(attribute string, value int, enums map[int]interface{}) error {
106

107 14
	if _, ok := enums[value]; ok {
108 14
		return nil
109
	}
110

111 14
	err := NewError("Validation Error", fmt.Sprintf(intInMap, value, attribute, enums), "elemental", http.StatusUnprocessableEntity)
112 14
	err.Data = map[string]string{"attribute": attribute}
113 14
	return err
114
}
115

116
// ValidateFloatInList validates if the string is in the list.
117
func ValidateFloatInList(attribute string, value float64, enums []float64) error {
118

119
	for _, v := range enums {
120 14
		if v == value {
121 14
			return nil
122
		}
123
	}
124

125 14
	err := NewError("Validation Error", fmt.Sprintf(floatInListFormat, value, attribute, enums), "elemental", http.StatusUnprocessableEntity)
126 14
	err.Data = map[string]string{"attribute": attribute}
127 14
	return err
128
}
129

130
// ValidateIntInList validates if the string is in the list.
131
func ValidateIntInList(attribute string, value int, enums []int) error {
132

133
	for _, v := range enums {
134 14
		if v == value {
135 14
			return nil
136
		}
137
	}
138

139 14
	err := NewError("Validation Error", fmt.Sprintf(intInListFormat, value, attribute, enums), "elemental", http.StatusUnprocessableEntity)
140 14
	err.Data = map[string]string{"attribute": attribute}
141 14
	return err
142
}
143

144
// ValidateRequiredInt validates is the int is set to 0.
145
func ValidateRequiredInt(attribute string, value int) error {
146

147 14
	if value == 0 {
148 14
		err := NewError("Validation Error", fmt.Sprintf(requiredIntFailFormat, attribute), "elemental", http.StatusUnprocessableEntity)
149 14
		err.Data = map[string]string{"attribute": attribute}
150 14
		return err
151
	}
152

153 14
	return nil
154
}
155

156
// ValidateRequiredFloat validates is the int is set to 0.
157
func ValidateRequiredFloat(attribute string, value float64) error {
158

159 14
	if value == 0.0 {
160 14
		err := NewError("Validation Error", fmt.Sprintf(requiredFloatFailFormat, attribute), "elemental", http.StatusUnprocessableEntity)
161 14
		err.Data = map[string]string{"attribute": attribute}
162 14
		return err
163
	}
164

165 14
	return nil
166
}
167

168
// ValidateRequiredExternal validates if the given value is null or not
169
func ValidateRequiredExternal(attribute string, value interface{}) error {
170 14
	var valueIsNil bool
171

172 14
	if value == nil {
173 14
		valueIsNil = true
174
	}
175

176 14
	if !valueIsNil {
177 14
		v := reflect.ValueOf(value)
178

179 14
		switch v.Kind() {
180 14
		case reflect.Slice, reflect.Map:
181 14
			valueIsNil = v.IsNil() || v.Len() == 0
182 14
		default:
183 14
			valueIsNil = v.Interface() == reflect.Zero(reflect.TypeOf(v.Interface())).Interface()
184
		}
185
	}
186

187 14
	if valueIsNil {
188 14
		err := NewError("Validation Error", fmt.Sprintf(requiredExternalFailFormat, attribute), "elemental", http.StatusUnprocessableEntity)
189 14
		err.Data = map[string]string{"attribute": attribute}
190 14
		return err
191
	}
192

193 14
	return nil
194
}
195

196
// ValidateMaximumFloat validates a float against a maximum value.
197
func ValidateMaximumFloat(attribute string, value float64, max float64, exclusive bool) error {
198

199 14
	if !exclusive && value > max {
200 14
		err := NewError("Validation Error", fmt.Sprintf(maximumFloatFailFormat, value, attribute, max), "elemental", http.StatusUnprocessableEntity)
201 14
		err.Data = map[string]string{"attribute": attribute}
202 14
		return err
203 14
	} else if exclusive && value >= max {
204 14
		err := NewError("Validation Error", fmt.Sprintf(maximumFloatExclusiveFailFormat, value, attribute, max), "elemental", http.StatusUnprocessableEntity)
205 14
		err.Data = map[string]string{"attribute": attribute}
206 14
		return err
207
	}
208

209 14
	return nil
210
}
211

212
// ValidateMinimumFloat validates a float against a maximum value.
213
func ValidateMinimumFloat(attribute string, value float64, min float64, exclusive bool) error {
214

215 14
	if !exclusive && value < min {
216 14
		err := NewError("Validation Error", fmt.Sprintf(minimumFloatFailFormat, value, attribute, min), "elemental", http.StatusUnprocessableEntity)
217 14
		err.Data = map[string]string{"attribute": attribute}
218 14
		return err
219

220 14
	} else if exclusive && value <= min {
221 14
		err := NewError("Validation Error", fmt.Sprintf(minimumFloatExclusiveFailFormat, value, attribute, min), "elemental", http.StatusUnprocessableEntity)
222 14
		err.Data = map[string]string{"attribute": attribute}
223 14
		return err
224
	}
225

226 14
	return nil
227
}
228

229
// ValidateMaximumInt validates a integer against a maximum value.
230
func ValidateMaximumInt(attribute string, value int, max int, exclusive bool) error {
231

232 14
	if !exclusive && value > max {
233 14
		err := NewError("Validation Error", fmt.Sprintf(maximumIntFailFormat, value, attribute, max), "elemental", http.StatusUnprocessableEntity)
234 14
		err.Data = map[string]string{"attribute": attribute}
235 14
		return err
236 14
	} else if exclusive && value >= max {
237 14
		err := NewError("Validation Error", fmt.Sprintf(maximumIntExclusiveFailFormat, value, attribute, max), "elemental", http.StatusUnprocessableEntity)
238 14
		err.Data = map[string]string{"attribute": attribute}
239 14
		return err
240
	}
241

242 14
	return nil
243
}
244

245
// ValidateMinimumInt validates a integer against a maximum value.
246
func ValidateMinimumInt(attribute string, value int, min int, exclusive bool) error {
247

248 14
	if !exclusive && value < min {
249 14
		err := NewError("Validation Error", fmt.Sprintf(minimumIntFailFormat, value, attribute, min), "elemental", http.StatusUnprocessableEntity)
250 14
		err.Data = map[string]string{"attribute": attribute}
251 14
		return err
252 14
	} else if exclusive && value <= min {
253 14
		err := NewError("Validation Error", fmt.Sprintf(minimumIntExclusiveFailFormat, value, attribute, min), "elemental", http.StatusUnprocessableEntity)
254 14
		err.Data = map[string]string{"attribute": attribute}
255 14
		return err
256
	}
257

258 14
	return nil
259
}
260

261
// ValidateRequiredString validates if the string is empty.
262
func ValidateRequiredString(attribute string, value string) error {
263

264 14
	if value == "" {
265 14
		err := NewError("Validation Error", fmt.Sprintf(requiredStringFailFormat, attribute), "elemental", http.StatusUnprocessableEntity)
266 14
		err.Data = map[string]string{"attribute": attribute}
267 14
		return err
268
	}
269

270 14
	return nil
271
}
272

273
// ValidateRequiredTime validates if the time is empty.
274
func ValidateRequiredTime(attribute string, value time.Time) error {
275

276 14
	var t time.Time
277 14
	if value.Equal(t) {
278 14
		err := NewError("Validation Error", fmt.Sprintf(requiredTimeFailFormat, attribute), "elemental", http.StatusUnprocessableEntity)
279 14
		err.Data = map[string]string{"attribute": attribute}
280 14
		return err
281
	}
282

283 14
	return nil
284
}
285

286
// ValidatePattern validates a string against a regular expression.
287
func ValidatePattern(attribute string, value string, pattern string, message string, required bool) error {
288

289 14
	if !required && value == "" {
290 14
		return nil
291
	}
292

293 14
	re := regexp.MustCompile(pattern)
294

295 14
	if !re.MatchString(value) {
296 14
		err := NewError("Validation Error", fmt.Sprintf(patternFailFormat, value, attribute, message), "elemental", http.StatusUnprocessableEntity)
297 14
		err.Data = map[string]string{"attribute": attribute}
298 14
		return err
299
	}
300

301 14
	return nil
302
}
303

304
// ValidateMinimumLength validates the minimum length of a string.
305
func ValidateMinimumLength(attribute string, value string, min int, exclusive bool) error {
306

307 14
	length := len([]rune(value))
308

309 14
	if !exclusive && length < min {
310 14
		err := NewError("Validation Error", fmt.Sprintf(minimumLengthFailFormat, value, attribute, min), "elemental", http.StatusUnprocessableEntity)
311 14
		err.Data = map[string]string{"attribute": attribute}
312 14
		return err
313 14
	} else if exclusive && length <= min {
314 14
		err := NewError("Validation Error", fmt.Sprintf(minimumLengthExclusiveFailFormat, value, attribute, min), "elemental", http.StatusUnprocessableEntity)
315 14
		err.Data = map[string]string{"attribute": attribute}
316 14
		return err
317
	}
318

319 14
	return nil
320
}
321

322
// ValidateMaximumLength validates the maximum length of a string.
323
func ValidateMaximumLength(attribute string, value string, max int, exclusive bool) error {
324

325 14
	length := len([]rune(value))
326

327 14
	if !exclusive && length > max {
328 14
		err := NewError("Validation Error", fmt.Sprintf(maximumLengthFailFormat, value, attribute, max), "elemental", http.StatusUnprocessableEntity)
329 14
		err.Data = map[string]string{"attribute": attribute}
330 14
		return err
331 14
	} else if exclusive && length >= max {
332 14
		err := NewError("Validation Error", fmt.Sprintf(maximumLengthExclusiveFailFormat, value, attribute, max), "elemental", http.StatusUnprocessableEntity)
333 14
		err.Data = map[string]string{"attribute": attribute}
334 14
		return err
335
	}
336

337 14
	return nil
338
}

Read our documentation on viewing source code .

Loading