safeshield 1.3.2__py3-none-any.whl → 1.4.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.
- {safeshield-1.3.2.dist-info → safeshield-1.4.3.dist-info}/METADATA +9 -1
- safeshield-1.4.3.dist-info/RECORD +31 -0
- validator/core/validator.py +7 -7
- validator/factory.py +4 -4
- validator/rules/__init__.py +6 -8
- validator/rules/array.py +23 -30
- validator/rules/base.py +32 -8
- validator/rules/basic.py +64 -165
- validator/rules/boolean.py +157 -0
- validator/rules/comparison.py +121 -31
- validator/rules/date.py +30 -14
- validator/rules/files.py +176 -64
- validator/rules/format.py +116 -25
- validator/rules/numeric.py +188 -0
- validator/rules/string.py +68 -9
- validator/rules/utilities.py +209 -34
- validator/services/rule_conflict.py +2 -2
- validator/services/rule_error_handler.py +4 -2
- validator/services/rule_preparer.py +12 -25
- safeshield-1.3.2.dist-info/RECORD +0 -31
- validator/rules/conditional.py +0 -165
- validator/rules/type.py +0 -49
- {safeshield-1.3.2.dist-info → safeshield-1.4.3.dist-info}/LICENSE +0 -0
- {safeshield-1.3.2.dist-info → safeshield-1.4.3.dist-info}/WHEEL +0 -0
- {safeshield-1.3.2.dist-info → safeshield-1.4.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from .base import Rule
|
|
2
|
+
from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
|
|
3
|
+
|
|
4
|
+
class BooleanRule(Rule):
|
|
5
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
6
|
+
if isinstance(value, bool):
|
|
7
|
+
return True
|
|
8
|
+
if isinstance(value, str):
|
|
9
|
+
return value.lower() in ['true', 'false', '1', '0', 'yes', 'no', 'on', 'off']
|
|
10
|
+
if isinstance(value, int):
|
|
11
|
+
return value in [0, 1]
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
15
|
+
return f"The :attribute field must be true or false."
|
|
16
|
+
|
|
17
|
+
class AcceptedRule(Rule):
|
|
18
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
19
|
+
value = self.get_field_value(value, value)
|
|
20
|
+
|
|
21
|
+
if isinstance(value, str):
|
|
22
|
+
return value.lower() in ['yes', 'on', '1', 1, True, 'true', 'True']
|
|
23
|
+
if isinstance(value, int):
|
|
24
|
+
return value == 1
|
|
25
|
+
if isinstance(value, bool):
|
|
26
|
+
return value
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
30
|
+
return f"The :attribute must be accepted."
|
|
31
|
+
|
|
32
|
+
class DeclinedRule(Rule):
|
|
33
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
34
|
+
value = self.get_field_value(value, value)
|
|
35
|
+
|
|
36
|
+
if isinstance(value, str):
|
|
37
|
+
return value.lower() in ['no', 'off', '0', 0, False, 'false', 'False']
|
|
38
|
+
if isinstance(value, int):
|
|
39
|
+
return value == 0
|
|
40
|
+
if isinstance(value, bool):
|
|
41
|
+
return not value
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
45
|
+
return f"The :attribute must be declined."
|
|
46
|
+
|
|
47
|
+
class AcceptedIfRule(AcceptedRule):
|
|
48
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
49
|
+
condition_met = False
|
|
50
|
+
|
|
51
|
+
if len(params) == 1 and callable(params[0]):
|
|
52
|
+
condition_met = params[0](self.validator.data)
|
|
53
|
+
elif len(params) == 1 and isinstance(params[0], bool):
|
|
54
|
+
condition_met = params[0]
|
|
55
|
+
else:
|
|
56
|
+
conditions = list(zip(params[::2], params[1::2]))
|
|
57
|
+
|
|
58
|
+
for other_field, expected_value in conditions:
|
|
59
|
+
if not other_field or expected_value is None:
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
actual_value = self.get_field_value(other_field, '')
|
|
63
|
+
|
|
64
|
+
if actual_value == expected_value:
|
|
65
|
+
condition_met = True
|
|
66
|
+
break
|
|
67
|
+
|
|
68
|
+
if condition_met:
|
|
69
|
+
return super().validate(field, value, params)
|
|
70
|
+
|
|
71
|
+
return True
|
|
72
|
+
|
|
73
|
+
class AcceptedUnlessRule(AcceptedRule):
|
|
74
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
75
|
+
if len(params) < 2:
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
other_field, other_value = params[0], params[1]
|
|
79
|
+
actual_value = self.get_field_value(other_field, '')
|
|
80
|
+
|
|
81
|
+
if actual_value == other_value:
|
|
82
|
+
return True
|
|
83
|
+
|
|
84
|
+
return super().validate(field, value, params)
|
|
85
|
+
|
|
86
|
+
class AcceptedAllIfRule(AcceptedRule):
|
|
87
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
88
|
+
if len(params) < 2:
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
|
|
92
|
+
|
|
93
|
+
all_conditions_met = all(
|
|
94
|
+
self.get_field_value(f) == v
|
|
95
|
+
for f, v in conditions
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if not all_conditions_met:
|
|
99
|
+
return True
|
|
100
|
+
|
|
101
|
+
return super().validate(field, value, params)
|
|
102
|
+
|
|
103
|
+
class DeclinedIfRule(DeclinedRule):
|
|
104
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
105
|
+
condition_met = False
|
|
106
|
+
|
|
107
|
+
if len(params) == 1 and callable(params[0]):
|
|
108
|
+
condition_met = params[0](self.validator.data)
|
|
109
|
+
elif len(params) == 1 and isinstance(params[0], bool):
|
|
110
|
+
condition_met = params[0]
|
|
111
|
+
else:
|
|
112
|
+
conditions = list(zip(params[::2], params[1::2]))
|
|
113
|
+
|
|
114
|
+
for other_field, expected_value in conditions:
|
|
115
|
+
if not other_field or expected_value is None:
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
actual_value = self.get_field_value(other_field, '')
|
|
119
|
+
|
|
120
|
+
if actual_value == expected_value:
|
|
121
|
+
condition_met = True
|
|
122
|
+
break
|
|
123
|
+
|
|
124
|
+
if condition_met:
|
|
125
|
+
return super().validate(field, value, params)
|
|
126
|
+
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
class DeclinedUnlessRule(DeclinedRule):
|
|
130
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
131
|
+
if len(params) < 2:
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
other_field, other_value = params[0], params[1]
|
|
135
|
+
actual_value = self.get_field_value(other_field, '')
|
|
136
|
+
|
|
137
|
+
if actual_value == other_value:
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
return super().validate(field, value, params)
|
|
141
|
+
|
|
142
|
+
class DeclinedAllIfRule(DeclinedRule):
|
|
143
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
144
|
+
if len(params) < 2:
|
|
145
|
+
return False
|
|
146
|
+
|
|
147
|
+
conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
|
|
148
|
+
|
|
149
|
+
all_conditions_met = all(
|
|
150
|
+
self.get_field_value(f) == v
|
|
151
|
+
for f, v in conditions
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if not all_conditions_met:
|
|
155
|
+
return True
|
|
156
|
+
|
|
157
|
+
return super().validate(field, value, params)
|
validator/rules/comparison.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
from .base import
|
|
2
|
-
from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
|
|
1
|
+
from .base import Rule
|
|
2
|
+
from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type, Callable
|
|
3
3
|
|
|
4
4
|
# =============================================
|
|
5
5
|
# COMPARISON VALIDATION RULES
|
|
6
6
|
# =============================================
|
|
7
7
|
|
|
8
|
-
class MinRule(
|
|
8
|
+
class MinRule(Rule):
|
|
9
9
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
10
10
|
if not params:
|
|
11
11
|
return False
|
|
@@ -29,7 +29,7 @@ class MinRule(ValidationRule):
|
|
|
29
29
|
def message(self, field: str, params: List[str]) -> str:
|
|
30
30
|
return f"The :attribute must be at least {params[0]}."
|
|
31
31
|
|
|
32
|
-
class MaxRule(
|
|
32
|
+
class MaxRule(Rule):
|
|
33
33
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
34
34
|
if not params or len(params) < 1:
|
|
35
35
|
return False
|
|
@@ -93,7 +93,7 @@ class MaxRule(ValidationRule):
|
|
|
93
93
|
return f"File :attribute must not exceed {params[0]} bytes"
|
|
94
94
|
return f"The :attribute must not exceed {params[0]}"
|
|
95
95
|
|
|
96
|
-
class BetweenRule(
|
|
96
|
+
class BetweenRule(Rule):
|
|
97
97
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
98
98
|
if len(params) != 2:
|
|
99
99
|
return False
|
|
@@ -139,7 +139,7 @@ class BetweenRule(ValidationRule):
|
|
|
139
139
|
return f"File :attribute must be between {params[0]} and {params[1]} bytes"
|
|
140
140
|
return f"The :attribute must be between {params[0]} and {params[1]}"
|
|
141
141
|
|
|
142
|
-
class SizeRule(
|
|
142
|
+
class SizeRule(Rule):
|
|
143
143
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
144
144
|
if not params or len(params) < 1:
|
|
145
145
|
return False
|
|
@@ -191,50 +191,140 @@ class SizeRule(ValidationRule):
|
|
|
191
191
|
|
|
192
192
|
return f"The :attribute must be exactly {params[0]}"
|
|
193
193
|
|
|
194
|
-
|
|
194
|
+
|
|
195
|
+
class UniqueRule(Rule):
|
|
195
196
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
196
|
-
if not params or not
|
|
197
|
+
if not params or not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
197
198
|
return False
|
|
198
199
|
|
|
200
|
+
table = params[0]
|
|
201
|
+
column = field if len(params) == 1 else params[1]
|
|
202
|
+
|
|
199
203
|
try:
|
|
200
|
-
|
|
201
|
-
|
|
204
|
+
ignore_id = None
|
|
205
|
+
if len(params) > 2 and params[2].startswith('ignore:'):
|
|
206
|
+
ignore_field = params[2].split(':')[1]
|
|
207
|
+
ignore_id = self.get_field_value(ignore_field)
|
|
208
|
+
return self.validator.db_manager.is_unique(table, column, value, ignore_id)
|
|
209
|
+
except Exception as e:
|
|
210
|
+
print(f"Database error in UniqueRule: {e}")
|
|
202
211
|
return False
|
|
203
|
-
|
|
204
|
-
return value.isdigit() and len(value) == digits
|
|
205
212
|
|
|
206
213
|
def message(self, field: str, params: List[str]) -> str:
|
|
207
|
-
return f"The :attribute
|
|
214
|
+
return f"The :attribute has already been taken."
|
|
208
215
|
|
|
209
|
-
class
|
|
216
|
+
class ExistsRule(Rule):
|
|
210
217
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
211
|
-
if
|
|
218
|
+
if not params or not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
212
219
|
return False
|
|
213
220
|
|
|
221
|
+
table = params[0]
|
|
222
|
+
column = field if len(params) == 1 else params[1]
|
|
223
|
+
|
|
214
224
|
try:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
225
|
+
return self.validator.db_manager.exists(table, column, value)
|
|
226
|
+
except Exception as e:
|
|
227
|
+
print(f"Database error in ExistsRule: {e}")
|
|
218
228
|
return False
|
|
219
|
-
|
|
220
|
-
return value.isdigit() and min_digits <= len(value) <= max_digits
|
|
221
229
|
|
|
222
230
|
def message(self, field: str, params: List[str]) -> str:
|
|
223
|
-
return f"The :attribute
|
|
231
|
+
return f"The selected :attribute is invalid."
|
|
232
|
+
|
|
233
|
+
class SameRule(Rule):
|
|
234
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
235
|
+
if not params:
|
|
236
|
+
return False
|
|
237
|
+
return value == self.get_field_value(params[0])
|
|
238
|
+
|
|
239
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
240
|
+
return f"The :attribute and {params[0]} must match."
|
|
224
241
|
|
|
225
|
-
class
|
|
242
|
+
class DifferentRule(Rule):
|
|
226
243
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
227
244
|
if not params:
|
|
228
245
|
return False
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
246
|
+
|
|
247
|
+
return str(value) != self.get_field_value(params[0])
|
|
248
|
+
|
|
249
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
250
|
+
return f"The :attribute and {params[0]} must be different."
|
|
251
|
+
|
|
252
|
+
class InRule(Rule):
|
|
253
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
254
|
+
allowed_values = self._parse_option_values(field, params)
|
|
255
|
+
return (str(value) in allowed_values or value in allowed_values)
|
|
256
|
+
|
|
257
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
258
|
+
allowed_values = self._parse_option_values(field, params)
|
|
259
|
+
return f"The selected :attribute must be in : {', '.join(map(str, allowed_values))}"
|
|
260
|
+
|
|
261
|
+
class NotInRule(Rule):
|
|
262
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
263
|
+
not_allowed_values = self._parse_option_values(field, params)
|
|
264
|
+
return str(value) not in not_allowed_values
|
|
265
|
+
|
|
266
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
267
|
+
not_allowed_values = self._parse_option_values(field, params)
|
|
268
|
+
return f"The selected :attribute must be not in : {', '.join(map(str, not_allowed_values))}"
|
|
269
|
+
|
|
270
|
+
class EnumRule(Rule):
|
|
271
|
+
def __init__(self, *params):
|
|
272
|
+
super().__init__()
|
|
273
|
+
self._params: List[str] = list(params)
|
|
274
|
+
self.allowed_values = self._parse_option_values(None, self._params, raise_for_error=False)
|
|
275
|
+
|
|
276
|
+
def exclude(self, *options):
|
|
277
|
+
except_values = self._parse_option_values(None, options, raise_for_error=False)
|
|
278
|
+
self.allowed_values = [value for value in self.allowed_values if value not in except_values]
|
|
279
|
+
return self
|
|
280
|
+
|
|
281
|
+
def only(self, *options):
|
|
282
|
+
only_values = self._parse_option_values(None, options, raise_for_error=False)
|
|
283
|
+
self.allowed_values = [value for value in self.allowed_values if value in only_values]
|
|
284
|
+
return self
|
|
285
|
+
|
|
286
|
+
def when(self,
|
|
287
|
+
condition: bool,
|
|
288
|
+
when_true: Callable[['EnumRule'], 'EnumRule'],
|
|
289
|
+
when_false: Optional[Callable[['EnumRule'], 'EnumRule']] = None
|
|
290
|
+
) -> 'EnumRule':
|
|
291
|
+
|
|
292
|
+
if condition:
|
|
293
|
+
return when_true(self)
|
|
294
|
+
elif when_false:
|
|
295
|
+
return when_false(self)
|
|
296
|
+
return self
|
|
297
|
+
|
|
298
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
299
|
+
return (str(value) in self.allowed_values or value in self.allowed_values)
|
|
300
|
+
|
|
301
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
302
|
+
allowed_values = self._parse_option_values(field, self.allowed_values)
|
|
303
|
+
return f"The :attribute must be one of: {', '.join(map(str, allowed_values))}"
|
|
304
|
+
|
|
305
|
+
class ContainsRule(Rule):
|
|
306
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
307
|
+
if not params:
|
|
237
308
|
return False
|
|
309
|
+
|
|
310
|
+
for search_value in params:
|
|
311
|
+
if isinstance(value, str) and search_value in value:
|
|
312
|
+
return True
|
|
313
|
+
|
|
314
|
+
if isinstance(value, (int, float)) and str(search_value) in str(value):
|
|
315
|
+
return True
|
|
316
|
+
|
|
317
|
+
if isinstance(value, (list, tuple, set)) and search_value in value:
|
|
318
|
+
return True
|
|
319
|
+
|
|
320
|
+
if isinstance(value, dict) and search_value in value.keys():
|
|
321
|
+
return True
|
|
322
|
+
|
|
323
|
+
return False
|
|
238
324
|
|
|
239
325
|
def message(self, field: str, params: List[str]) -> str:
|
|
240
|
-
|
|
326
|
+
if len(params) == 1:
|
|
327
|
+
return f"The {field} must contain {params[0]}"
|
|
328
|
+
|
|
329
|
+
joined_params = ", ".join(params[:-1]) + f" or {params[-1]}"
|
|
330
|
+
return f"The {field} must contain at least one of: {joined_params}"
|
validator/rules/date.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
from .base import
|
|
1
|
+
from .base import Rule
|
|
2
2
|
from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
import zoneinfo
|
|
4
5
|
from dateutil.parser import parse
|
|
5
6
|
|
|
6
|
-
class DateRule(
|
|
7
|
+
class DateRule(Rule):
|
|
7
8
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
8
9
|
if not isinstance(value, str):
|
|
9
10
|
return False
|
|
@@ -17,16 +18,15 @@ class DateRule(ValidationRule):
|
|
|
17
18
|
def message(self, field: str, params: List[str]) -> str:
|
|
18
19
|
return f"The :attribute is not a valid date."
|
|
19
20
|
|
|
20
|
-
class DateEqualsRule(
|
|
21
|
+
class DateEqualsRule(Rule):
|
|
21
22
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
22
23
|
if not params or not isinstance(value, str):
|
|
23
24
|
return False
|
|
24
25
|
|
|
25
|
-
value = self.get_field_value(value, value)
|
|
26
|
-
|
|
27
26
|
try:
|
|
28
27
|
date1 = parse(value)
|
|
29
28
|
|
|
29
|
+
params = list(params)
|
|
30
30
|
params[0] = self.get_field_value(params[0], params[0])
|
|
31
31
|
|
|
32
32
|
date2 = parse(params[0])
|
|
@@ -37,7 +37,7 @@ class DateEqualsRule(ValidationRule):
|
|
|
37
37
|
def message(self, field: str, params: List[str]) -> str:
|
|
38
38
|
return f"The :attribute must be equal to {params[0]}."
|
|
39
39
|
|
|
40
|
-
class AfterRule(
|
|
40
|
+
class AfterRule(Rule):
|
|
41
41
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
42
42
|
if not params or len(params) < 1:
|
|
43
43
|
return False
|
|
@@ -51,7 +51,8 @@ class AfterRule(ValidationRule):
|
|
|
51
51
|
else:
|
|
52
52
|
return False
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
|
|
55
|
+
params = list(params)# Parse comparison date
|
|
55
56
|
params[0] = self.get_field_value(params[0], params[0])
|
|
56
57
|
compare_date = parse(params[0])
|
|
57
58
|
|
|
@@ -63,11 +64,10 @@ class AfterRule(ValidationRule):
|
|
|
63
64
|
def message(self, field: str, params: List[str]) -> str:
|
|
64
65
|
return f"The :attribute must be after {params[0]}"
|
|
65
66
|
|
|
66
|
-
class AfterOrEqualRule(
|
|
67
|
+
class AfterOrEqualRule(Rule):
|
|
67
68
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
68
69
|
if not params or len(params) < 1:
|
|
69
70
|
return False
|
|
70
|
-
|
|
71
71
|
try:
|
|
72
72
|
if isinstance(value, str):
|
|
73
73
|
date_value = parse(value)
|
|
@@ -76,18 +76,19 @@ class AfterOrEqualRule(ValidationRule):
|
|
|
76
76
|
else:
|
|
77
77
|
return False
|
|
78
78
|
|
|
79
|
+
params = list(params)
|
|
79
80
|
params[0] = self.get_field_value(params[0], params[0])
|
|
80
81
|
compare_date = parse(params[0])
|
|
81
82
|
|
|
82
83
|
return date_value >= compare_date
|
|
83
84
|
|
|
84
|
-
except (ValueError, TypeError):
|
|
85
|
+
except (ValueError, TypeError) as e:
|
|
85
86
|
return False
|
|
86
87
|
|
|
87
88
|
def message(self, field: str, params: List[str]) -> str:
|
|
88
89
|
return f"The :attribute must be after or equal to {params[0]}"
|
|
89
90
|
|
|
90
|
-
class BeforeRule(
|
|
91
|
+
class BeforeRule(Rule):
|
|
91
92
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
92
93
|
if not params or len(params) < 1:
|
|
93
94
|
return False
|
|
@@ -102,6 +103,7 @@ class BeforeRule(ValidationRule):
|
|
|
102
103
|
else:
|
|
103
104
|
return False
|
|
104
105
|
|
|
106
|
+
params = list(params)
|
|
105
107
|
params[0] = self.get_field_value(params[0], params[0])
|
|
106
108
|
compare_date = parse(params[0])
|
|
107
109
|
|
|
@@ -113,7 +115,7 @@ class BeforeRule(ValidationRule):
|
|
|
113
115
|
def message(self, field: str, params: List[str]) -> str:
|
|
114
116
|
return f"The :attribute must be before {params[0]}"
|
|
115
117
|
|
|
116
|
-
class BeforeOrEqualRule(
|
|
118
|
+
class BeforeOrEqualRule(Rule):
|
|
117
119
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
118
120
|
if not params or len(params) < 1:
|
|
119
121
|
return False
|
|
@@ -128,6 +130,7 @@ class BeforeOrEqualRule(ValidationRule):
|
|
|
128
130
|
else:
|
|
129
131
|
return False
|
|
130
132
|
|
|
133
|
+
params = list(params)
|
|
131
134
|
params[0] = self.get_field_value(params[0], params[0])
|
|
132
135
|
compare_date = parse(params[0])
|
|
133
136
|
|
|
@@ -139,7 +142,7 @@ class BeforeOrEqualRule(ValidationRule):
|
|
|
139
142
|
def message(self, field: str, params: List[str]) -> str:
|
|
140
143
|
return f"The :attribute must be before or equal to {params[0]}"
|
|
141
144
|
|
|
142
|
-
class DateFormatRule(
|
|
145
|
+
class DateFormatRule(Rule):
|
|
143
146
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
144
147
|
if not params or len(params) < 1 or not isinstance(value, str):
|
|
145
148
|
return False
|
|
@@ -151,4 +154,17 @@ class DateFormatRule(ValidationRule):
|
|
|
151
154
|
return False
|
|
152
155
|
|
|
153
156
|
def message(self, field: str, params: List[str]) -> str:
|
|
154
|
-
return f"The :attribute must match the format {params[0]}"
|
|
157
|
+
return f"The :attribute must match the format {params[0]}"
|
|
158
|
+
|
|
159
|
+
class TimezoneRule(Rule):
|
|
160
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
161
|
+
if not isinstance(value, str):
|
|
162
|
+
return False
|
|
163
|
+
try:
|
|
164
|
+
zoneinfo.ZoneInfo(value)
|
|
165
|
+
return True
|
|
166
|
+
except zoneinfo.ZoneInfoNotFoundError:
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
170
|
+
return f"The :attribute must be a valid timezone."
|