safeshield 1.5.1__py3-none-any.whl → 1.5.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of safeshield might be problematic. Click here for more details.
- {safeshield-1.5.1.dist-info → safeshield-1.5.3.dist-info}/METADATA +1 -1
- safeshield-1.5.3.dist-info/RECORD +31 -0
- validator/core/validator.py +21 -19
- validator/rules/array.py +46 -12
- validator/rules/base.py +42 -6
- validator/rules/basic.py +46 -4
- validator/rules/boolean.py +56 -57
- validator/rules/comparison.py +126 -34
- validator/rules/date.py +79 -27
- validator/rules/files.py +52 -11
- validator/rules/format.py +9 -0
- validator/rules/numeric.py +105 -36
- validator/rules/string.py +54 -9
- validator/rules/utilities.py +294 -131
- validator/services/rule_error_handler.py +24 -208
- validator/services/rule_preparer.py +21 -7
- safeshield-1.5.1.dist-info/RECORD +0 -31
- {safeshield-1.5.1.dist-info → safeshield-1.5.3.dist-info}/LICENSE +0 -0
- {safeshield-1.5.1.dist-info → safeshield-1.5.3.dist-info}/WHEEL +0 -0
- {safeshield-1.5.1.dist-info → safeshield-1.5.3.dist-info}/top_level.txt +0 -0
validator/rules/comparison.py
CHANGED
|
@@ -6,10 +6,9 @@ from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type, Callable
|
|
|
6
6
|
# =============================================
|
|
7
7
|
|
|
8
8
|
class MinRule(Rule):
|
|
9
|
+
_count_parameter = 1
|
|
10
|
+
|
|
9
11
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
10
|
-
if not params:
|
|
11
|
-
return False
|
|
12
|
-
|
|
13
12
|
try:
|
|
14
13
|
min_val = float(params[0])
|
|
15
14
|
except ValueError:
|
|
@@ -28,12 +27,20 @@ class MinRule(Rule):
|
|
|
28
27
|
|
|
29
28
|
def message(self, field: str, params: List[str]) -> str:
|
|
30
29
|
return f"The :attribute must be at least :min."
|
|
30
|
+
|
|
31
|
+
def replacements(self, field, value):
|
|
32
|
+
replacements = {
|
|
33
|
+
':attribute': self._get_display_name(field),
|
|
34
|
+
':input': value,
|
|
35
|
+
':min': self._params[0],
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return replacements
|
|
31
39
|
|
|
32
40
|
class MaxRule(Rule):
|
|
41
|
+
_count_parameter = 1
|
|
42
|
+
|
|
33
43
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
34
|
-
if not params or len(params) < 1:
|
|
35
|
-
return False
|
|
36
|
-
|
|
37
44
|
try:
|
|
38
45
|
max_val = float(params[0])
|
|
39
46
|
|
|
@@ -91,12 +98,20 @@ class MaxRule(Rule):
|
|
|
91
98
|
if any(hasattr(value, attr) for attr in file_attrs):
|
|
92
99
|
return f"File :attribute must not exceed :max bytes"
|
|
93
100
|
return f"The :attribute must not exceed :max"
|
|
101
|
+
|
|
102
|
+
def replacements(self, field, value):
|
|
103
|
+
replacements = {
|
|
104
|
+
':attribute': self._get_display_name(field),
|
|
105
|
+
':input': value,
|
|
106
|
+
':max': self._params[0],
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return replacements
|
|
94
110
|
|
|
95
111
|
class BetweenRule(Rule):
|
|
112
|
+
_count_parameter = 2
|
|
113
|
+
|
|
96
114
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
97
|
-
if len(params) != 2:
|
|
98
|
-
return False
|
|
99
|
-
|
|
100
115
|
try:
|
|
101
116
|
min_val = float(params[0])
|
|
102
117
|
max_val = float(params[1])
|
|
@@ -135,14 +150,23 @@ class BetweenRule(Rule):
|
|
|
135
150
|
def message(self, field: str, params: List[str]) -> str:
|
|
136
151
|
value = self.get_field_value(field)
|
|
137
152
|
if hasattr(value, 'content_length') or hasattr(value, 'size'):
|
|
138
|
-
return f"File :attribute must be between
|
|
139
|
-
return f"The :attribute must be between
|
|
153
|
+
return f"File :attribute must be between :min and :max bytes"
|
|
154
|
+
return f"The :attribute must be between :min and :max"
|
|
155
|
+
|
|
156
|
+
def replacements(self, field, value):
|
|
157
|
+
replacements = {
|
|
158
|
+
':attribute': self._get_display_name(field),
|
|
159
|
+
':input': value,
|
|
160
|
+
':min': self._params[0],
|
|
161
|
+
':max': self._params[1],
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return replacements
|
|
140
165
|
|
|
141
166
|
class SizeRule(Rule):
|
|
167
|
+
_count_parameter = 1
|
|
168
|
+
|
|
142
169
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
143
|
-
if not params or len(params) < 1:
|
|
144
|
-
return False
|
|
145
|
-
|
|
146
170
|
try:
|
|
147
171
|
target_size = float(params[0])
|
|
148
172
|
|
|
@@ -181,19 +205,29 @@ class SizeRule(Rule):
|
|
|
181
205
|
def message(self, field: str, params: List[str]) -> str:
|
|
182
206
|
value = self.get_field_value(field)
|
|
183
207
|
if value is None:
|
|
184
|
-
return f"The :attribute must be exactly
|
|
208
|
+
return f"The :attribute must be exactly :size"
|
|
185
209
|
|
|
186
210
|
# Check for file attributes
|
|
187
211
|
file_attrs = ['content_length', 'size', 'fileno']
|
|
188
212
|
if any(hasattr(value, attr) for attr in file_attrs):
|
|
189
|
-
return f"File :attribute must be exactly
|
|
213
|
+
return f"File :attribute must be exactly :size bytes"
|
|
190
214
|
|
|
191
|
-
return f"The :attribute must be exactly
|
|
215
|
+
return f"The :attribute must be exactly :size"
|
|
192
216
|
|
|
217
|
+
def replacements(self, field, value):
|
|
218
|
+
replacements = {
|
|
219
|
+
':attribute': self._get_display_name(field),
|
|
220
|
+
':input': value,
|
|
221
|
+
':size': self._params[0],
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return replacements
|
|
193
225
|
|
|
194
226
|
class UniqueRule(Rule):
|
|
227
|
+
_count_parameter = 1
|
|
228
|
+
|
|
195
229
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
196
|
-
if not
|
|
230
|
+
if not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
197
231
|
return False
|
|
198
232
|
|
|
199
233
|
table = params[0]
|
|
@@ -213,8 +247,10 @@ class UniqueRule(Rule):
|
|
|
213
247
|
return f"The :attribute has already been taken."
|
|
214
248
|
|
|
215
249
|
class ExistsRule(Rule):
|
|
250
|
+
_count_parameter = 1
|
|
251
|
+
|
|
216
252
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
217
|
-
if not
|
|
253
|
+
if not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
218
254
|
return False
|
|
219
255
|
|
|
220
256
|
table = params[0]
|
|
@@ -230,15 +266,28 @@ class ExistsRule(Rule):
|
|
|
230
266
|
return f"The selected :attribute is invalid."
|
|
231
267
|
|
|
232
268
|
class SameRule(Rule):
|
|
269
|
+
_count_parameter = 1
|
|
270
|
+
|
|
233
271
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
234
272
|
if not params:
|
|
235
273
|
return False
|
|
236
|
-
return value == self.get_field_value(params[0])
|
|
274
|
+
return value == self.get_field_value(params[0], None)
|
|
237
275
|
|
|
238
276
|
def message(self, field: str, params: List[str]) -> str:
|
|
239
277
|
return f"The :attribute and :other must match."
|
|
278
|
+
|
|
279
|
+
def replacements(self, field, value):
|
|
280
|
+
replacements = {
|
|
281
|
+
':attribute': self._get_display_name(field),
|
|
282
|
+
':input': value,
|
|
283
|
+
':other': self._get_display_name(self._params[0]),
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return replacements
|
|
240
287
|
|
|
241
288
|
class DifferentRule(Rule):
|
|
289
|
+
_count_parameter = 1
|
|
290
|
+
|
|
242
291
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
243
292
|
if not params:
|
|
244
293
|
return False
|
|
@@ -247,26 +296,56 @@ class DifferentRule(Rule):
|
|
|
247
296
|
|
|
248
297
|
def message(self, field: str, params: List[str]) -> str:
|
|
249
298
|
return f"The :attribute and :other must be different."
|
|
299
|
+
|
|
300
|
+
def replacements(self, field, value):
|
|
301
|
+
replacements = {
|
|
302
|
+
':attribute': self._get_display_name(field),
|
|
303
|
+
':input': value,
|
|
304
|
+
':other': self._get_display_name(self._params[0]),
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return replacements
|
|
250
308
|
|
|
251
309
|
class InRule(Rule):
|
|
310
|
+
_count_parameter = 1
|
|
311
|
+
|
|
252
312
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
253
313
|
allowed_values = self._parse_option_values(field, params)
|
|
254
314
|
return (str(value) in allowed_values or value in allowed_values)
|
|
255
315
|
|
|
256
316
|
def message(self, field: str, params: List[str]) -> str:
|
|
257
|
-
|
|
258
|
-
|
|
317
|
+
return f"The selected :attribute must be in : :values"
|
|
318
|
+
|
|
319
|
+
def replacements(self, field, value):
|
|
320
|
+
replacements = {
|
|
321
|
+
':attribute': self._get_display_name(field),
|
|
322
|
+
':input': value,
|
|
323
|
+
':values': ', '.join(self._get_display_name(self._params)),
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return replacements
|
|
259
327
|
|
|
260
328
|
class NotInRule(Rule):
|
|
329
|
+
_count_parameter = 1
|
|
330
|
+
|
|
261
331
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
262
|
-
|
|
263
|
-
return str(value) not in not_allowed_values
|
|
332
|
+
return not InRule.validate(self, field, value, params=params)
|
|
264
333
|
|
|
265
334
|
def message(self, field: str, params: List[str]) -> str:
|
|
266
|
-
|
|
267
|
-
|
|
335
|
+
return f"The selected :attribute must be not in : :values"
|
|
336
|
+
|
|
337
|
+
def replacements(self, field, value):
|
|
338
|
+
replacements = {
|
|
339
|
+
':attribute': self._get_display_name(field),
|
|
340
|
+
':input': value,
|
|
341
|
+
':values': ', '.join(self._get_display_name(self._params)),
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return replacements
|
|
268
345
|
|
|
269
346
|
class EnumRule(Rule):
|
|
347
|
+
_count_parameter = 1
|
|
348
|
+
|
|
270
349
|
def __init__(self, *params):
|
|
271
350
|
super().__init__()
|
|
272
351
|
self._params: List[str] = list(params)
|
|
@@ -299,13 +378,21 @@ class EnumRule(Rule):
|
|
|
299
378
|
|
|
300
379
|
def message(self, field: str, params: List[str]) -> str:
|
|
301
380
|
allowed_values = self._parse_option_values(field, self.allowed_values)
|
|
302
|
-
return f"The :attribute must be one of:
|
|
381
|
+
return f"The :attribute must be one of: :values"
|
|
382
|
+
|
|
383
|
+
def replacements(self, field, value):
|
|
384
|
+
replacements = {
|
|
385
|
+
':attribute': self._get_display_name(field),
|
|
386
|
+
':input': value,
|
|
387
|
+
':values': ', '.join(map(str, self.allowed_values)),
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return replacements
|
|
303
391
|
|
|
304
392
|
class ContainsRule(Rule):
|
|
393
|
+
_count_parameter = 1
|
|
394
|
+
|
|
305
395
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
306
|
-
if not params:
|
|
307
|
-
return False
|
|
308
|
-
|
|
309
396
|
for search_value in params:
|
|
310
397
|
if isinstance(value, str) and search_value in value:
|
|
311
398
|
return True
|
|
@@ -322,8 +409,13 @@ class ContainsRule(Rule):
|
|
|
322
409
|
return False
|
|
323
410
|
|
|
324
411
|
def message(self, field: str, params: List[str]) -> str:
|
|
325
|
-
|
|
326
|
-
|
|
412
|
+
return f"The :attribute must contain at least one of: :values"
|
|
413
|
+
|
|
414
|
+
def replacements(self, field, value):
|
|
415
|
+
replacements = {
|
|
416
|
+
':attribute': self._get_display_name(field),
|
|
417
|
+
':input': value,
|
|
418
|
+
':values': ', '.join(self._params),
|
|
419
|
+
}
|
|
327
420
|
|
|
328
|
-
|
|
329
|
-
return f"The {field} must contain at least one of: {joined_params}"
|
|
421
|
+
return replacements
|
validator/rules/date.py
CHANGED
|
@@ -19,12 +19,17 @@ class DateRule(Rule):
|
|
|
19
19
|
return f"The :attribute is not a valid date."
|
|
20
20
|
|
|
21
21
|
class DateEqualsRule(Rule):
|
|
22
|
+
_count_parameter = 1
|
|
23
|
+
|
|
22
24
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
23
|
-
if not params or not isinstance(value, str):
|
|
24
|
-
return False
|
|
25
25
|
|
|
26
26
|
try:
|
|
27
|
-
|
|
27
|
+
if isinstance(value, str):
|
|
28
|
+
date1 = parse(value)
|
|
29
|
+
elif isinstance(value, datetime):
|
|
30
|
+
date1 = value
|
|
31
|
+
else:
|
|
32
|
+
return False
|
|
28
33
|
|
|
29
34
|
params = list(params)
|
|
30
35
|
params[0] = self.get_field_value(params[0], params[0])
|
|
@@ -35,15 +40,22 @@ class DateEqualsRule(Rule):
|
|
|
35
40
|
return False
|
|
36
41
|
|
|
37
42
|
def message(self, field: str, params: List[str]) -> str:
|
|
38
|
-
return f"The :attribute must be equal to
|
|
43
|
+
return f"The :attribute must be equal to :value."
|
|
44
|
+
|
|
45
|
+
def replacements(self, field, value):
|
|
46
|
+
replacements = {
|
|
47
|
+
':attribute': self._get_display_name(field),
|
|
48
|
+
':input': value,
|
|
49
|
+
':value': self.get_field_value(self._params[0], self._params[0])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return replacements
|
|
39
53
|
|
|
40
54
|
class AfterRule(Rule):
|
|
55
|
+
_count_parameter = 1
|
|
56
|
+
|
|
41
57
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
42
|
-
if not params or len(params) < 1:
|
|
43
|
-
return False
|
|
44
|
-
|
|
45
58
|
try:
|
|
46
|
-
# Parse input date
|
|
47
59
|
if isinstance(value, str):
|
|
48
60
|
date_value = parse(value)
|
|
49
61
|
elif isinstance(value, datetime):
|
|
@@ -62,12 +74,21 @@ class AfterRule(Rule):
|
|
|
62
74
|
return False
|
|
63
75
|
|
|
64
76
|
def message(self, field: str, params: List[str]) -> str:
|
|
65
|
-
return f"The :attribute must be after
|
|
77
|
+
return f"The :attribute must be after :value"
|
|
78
|
+
|
|
79
|
+
def replacements(self, field, value):
|
|
80
|
+
replacements = {
|
|
81
|
+
':attribute': self._get_display_name(field),
|
|
82
|
+
':input': value,
|
|
83
|
+
':value': self.get_field_value(self._params[0], self._params[0])
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return replacements
|
|
66
87
|
|
|
67
88
|
class AfterOrEqualRule(Rule):
|
|
89
|
+
_count_parameter = 1
|
|
90
|
+
|
|
68
91
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
69
|
-
if not params or len(params) < 1:
|
|
70
|
-
return False
|
|
71
92
|
try:
|
|
72
93
|
if isinstance(value, str):
|
|
73
94
|
date_value = parse(value)
|
|
@@ -86,13 +107,21 @@ class AfterOrEqualRule(Rule):
|
|
|
86
107
|
return False
|
|
87
108
|
|
|
88
109
|
def message(self, field: str, params: List[str]) -> str:
|
|
89
|
-
return f"The :attribute must be after or equal to
|
|
110
|
+
return f"The :attribute must be after or equal to :value"
|
|
111
|
+
|
|
112
|
+
def replacements(self, field, value):
|
|
113
|
+
replacements = {
|
|
114
|
+
':attribute': self._get_display_name(field),
|
|
115
|
+
':input': value,
|
|
116
|
+
':value': self.get_field_value(self._params[0], self._params[0])
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return replacements
|
|
90
120
|
|
|
91
121
|
class BeforeRule(Rule):
|
|
122
|
+
_count_parameter = 1
|
|
123
|
+
|
|
92
124
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
93
|
-
if not params or len(params) < 1:
|
|
94
|
-
return False
|
|
95
|
-
|
|
96
125
|
value = self.get_field_value(value, value)
|
|
97
126
|
|
|
98
127
|
try:
|
|
@@ -104,7 +133,7 @@ class BeforeRule(Rule):
|
|
|
104
133
|
return False
|
|
105
134
|
|
|
106
135
|
params = list(params)
|
|
107
|
-
params[0] = self.get_field_value(params[0], params[0])
|
|
136
|
+
params[0] = self.get_field_value(params[0], params[0])
|
|
108
137
|
compare_date = parse(params[0])
|
|
109
138
|
|
|
110
139
|
return date_value < compare_date
|
|
@@ -113,13 +142,21 @@ class BeforeRule(Rule):
|
|
|
113
142
|
return False
|
|
114
143
|
|
|
115
144
|
def message(self, field: str, params: List[str]) -> str:
|
|
116
|
-
return f"The :attribute must be before
|
|
145
|
+
return f"The :attribute must be before :value"
|
|
146
|
+
|
|
147
|
+
def replacements(self, field, value):
|
|
148
|
+
replacements = {
|
|
149
|
+
':attribute': self._get_display_name(field),
|
|
150
|
+
':input': value,
|
|
151
|
+
':value': self.get_field_value(self._params[0], self._params[0])
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return replacements
|
|
117
155
|
|
|
118
156
|
class BeforeOrEqualRule(Rule):
|
|
157
|
+
_count_parameter = 1
|
|
158
|
+
|
|
119
159
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
120
|
-
if not params or len(params) < 1:
|
|
121
|
-
return False
|
|
122
|
-
|
|
123
160
|
value = self.get_field_value(value, value)
|
|
124
161
|
|
|
125
162
|
try:
|
|
@@ -140,13 +177,21 @@ class BeforeOrEqualRule(Rule):
|
|
|
140
177
|
return False
|
|
141
178
|
|
|
142
179
|
def message(self, field: str, params: List[str]) -> str:
|
|
143
|
-
return f"The :attribute must be before or equal to
|
|
180
|
+
return f"The :attribute must be before or equal to :value"
|
|
181
|
+
|
|
182
|
+
def replacements(self, field, value):
|
|
183
|
+
replacements = {
|
|
184
|
+
':attribute': self._get_display_name(field),
|
|
185
|
+
':input': value,
|
|
186
|
+
':value': self.get_field_value(self._params[0], self._params[0])
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return replacements
|
|
144
190
|
|
|
145
191
|
class DateFormatRule(Rule):
|
|
192
|
+
_count_parameter = 1
|
|
193
|
+
|
|
146
194
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
147
|
-
if not params or len(params) < 1 or not isinstance(value, str):
|
|
148
|
-
return False
|
|
149
|
-
|
|
150
195
|
try:
|
|
151
196
|
datetime.strptime(value, params[0])
|
|
152
197
|
return True
|
|
@@ -154,12 +199,19 @@ class DateFormatRule(Rule):
|
|
|
154
199
|
return False
|
|
155
200
|
|
|
156
201
|
def message(self, field: str, params: List[str]) -> str:
|
|
157
|
-
return f"The :attribute must match the format
|
|
202
|
+
return f"The :attribute must match the format :format"
|
|
203
|
+
|
|
204
|
+
def replacements(self, field, value):
|
|
205
|
+
replacements = {
|
|
206
|
+
':attribute': self._get_display_name(field),
|
|
207
|
+
':input': value,
|
|
208
|
+
':format': self.get_field_value(self._params[0], self._params[0])
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return replacements
|
|
158
212
|
|
|
159
213
|
class TimezoneRule(Rule):
|
|
160
214
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
161
|
-
if not isinstance(value, str):
|
|
162
|
-
return False
|
|
163
215
|
try:
|
|
164
216
|
zoneinfo.ZoneInfo(value)
|
|
165
217
|
return True
|
validator/rules/files.py
CHANGED
|
@@ -34,7 +34,7 @@ class FileRule(Rule):
|
|
|
34
34
|
class DimensionsRule(Rule):
|
|
35
35
|
def __init__(self, *params):
|
|
36
36
|
super().__init__(*params)
|
|
37
|
-
|
|
37
|
+
self._count_parameter = 1
|
|
38
38
|
self._constraints = {
|
|
39
39
|
'min_width': 0,
|
|
40
40
|
'min_height': 0,
|
|
@@ -44,7 +44,7 @@ class DimensionsRule(Rule):
|
|
|
44
44
|
'height': None,
|
|
45
45
|
'ratio': None
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
def maxWidth(self, value: int) -> 'DimensionsRule':
|
|
49
49
|
self._constraints['width'] = None
|
|
50
50
|
self._constraints['max_width'] = value
|
|
@@ -195,11 +195,25 @@ class DimensionsRule(Rule):
|
|
|
195
195
|
|
|
196
196
|
return f"The :attribute image must satisfy: {', '.join(constraints)}"
|
|
197
197
|
|
|
198
|
+
def replacements(self, field, value):
|
|
199
|
+
replacements = {
|
|
200
|
+
':attribute': self._get_display_name(field),
|
|
201
|
+
':input': value,
|
|
202
|
+
':width': self._constraints['width'],
|
|
203
|
+
':min_width': self._constraints['min_width'],
|
|
204
|
+
':max_width': self._constraints['max_width'],
|
|
205
|
+
':height': self._constraints['height'],
|
|
206
|
+
':min_height': self._constraints['min_height'],
|
|
207
|
+
':max_height': self._constraints['max_height'],
|
|
208
|
+
':ratio': self._constraints['ratio'],
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return replacements
|
|
212
|
+
|
|
198
213
|
class ExtensionsRule(Rule):
|
|
214
|
+
_count_parameter = 1
|
|
215
|
+
|
|
199
216
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
200
|
-
if not params:
|
|
201
|
-
return False
|
|
202
|
-
|
|
203
217
|
filename = (
|
|
204
218
|
value.filename if hasattr(value, 'filename')
|
|
205
219
|
else str(value)
|
|
@@ -212,7 +226,16 @@ class ExtensionsRule(Rule):
|
|
|
212
226
|
return ext in [e.lower().strip() for e in params]
|
|
213
227
|
|
|
214
228
|
def message(self, field: str, params: List[str]) -> str:
|
|
215
|
-
return f"File :attribute must have one of these extensions:
|
|
229
|
+
return f"File :attribute must have one of these extensions: :values"
|
|
230
|
+
|
|
231
|
+
def replacements(self, field, value):
|
|
232
|
+
replacements = {
|
|
233
|
+
':attribute': self._get_display_name(field),
|
|
234
|
+
':input': value,
|
|
235
|
+
':values': ', '.join(self._params)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return replacements
|
|
216
239
|
|
|
217
240
|
class ImageRule(Rule):
|
|
218
241
|
VALID_EXTENSIONS = {'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'}
|
|
@@ -243,10 +266,9 @@ class ImageRule(Rule):
|
|
|
243
266
|
return f"The :attribute must be a valid image file (JPEG, PNG, GIF, BMP, or WebP)"
|
|
244
267
|
|
|
245
268
|
class MimeTypesRule(Rule):
|
|
269
|
+
_count_parameter = 1
|
|
270
|
+
|
|
246
271
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
247
|
-
if not params:
|
|
248
|
-
return False
|
|
249
|
-
|
|
250
272
|
# Check from content_type attribute
|
|
251
273
|
if hasattr(value, 'content_type'):
|
|
252
274
|
return value.content_type in params
|
|
@@ -258,10 +280,20 @@ class MimeTypesRule(Rule):
|
|
|
258
280
|
return False
|
|
259
281
|
|
|
260
282
|
def message(self, field: str, params: List[str]) -> str:
|
|
261
|
-
return f"File :attribute must be one of these types:
|
|
283
|
+
return f"File :attribute must be one of these types: :values"
|
|
284
|
+
|
|
285
|
+
def replacements(self, field, value):
|
|
286
|
+
replacements = {
|
|
287
|
+
':attribute': self._get_display_name(field),
|
|
288
|
+
':input': value,
|
|
289
|
+
':values': ', '.join(self._params)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return replacements
|
|
262
293
|
|
|
263
294
|
class MimeTypeByExtensionRule(Rule):
|
|
264
295
|
_name = 'mimes'
|
|
296
|
+
_count_parameter = 1
|
|
265
297
|
|
|
266
298
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
267
299
|
if value is None or not hasattr(value, 'filename'):
|
|
@@ -276,4 +308,13 @@ class MimeTypeByExtensionRule(Rule):
|
|
|
276
308
|
return mime_type in params if mime_type else False
|
|
277
309
|
|
|
278
310
|
def message(self, field: str, params: List[str]) -> str:
|
|
279
|
-
return f"The :attribute must be one of these types:
|
|
311
|
+
return f"The :attribute must be one of these types: :values"
|
|
312
|
+
|
|
313
|
+
def replacements(self, field, value):
|
|
314
|
+
replacements = {
|
|
315
|
+
':attribute': self._get_display_name(field),
|
|
316
|
+
':input': value,
|
|
317
|
+
':values': ', '.join(self._params)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return replacements
|
validator/rules/format.py
CHANGED
|
@@ -122,6 +122,15 @@ class EmailRule(Rule):
|
|
|
122
122
|
base_msg += " (Unicode allowed)"
|
|
123
123
|
|
|
124
124
|
return f"{base_msg}."
|
|
125
|
+
|
|
126
|
+
def replacements(self, field, value):
|
|
127
|
+
replacements = {
|
|
128
|
+
':attribute': self._get_display_name(field),
|
|
129
|
+
':input': value,
|
|
130
|
+
':values': ', '.join(self._params if self._params else ['rfc']),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return replacements
|
|
125
134
|
|
|
126
135
|
class UrlRule(Rule):
|
|
127
136
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|