safeshield 1.2.1__py3-none-any.whl → 1.3.2__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.2.1.dist-info → safeshield-1.3.2.dist-info}/METADATA +7 -1
- safeshield-1.3.2.dist-info/RECORD +31 -0
- validator/core/validator.py +3 -3
- validator/database/manager.py +6 -1
- validator/rules/array.py +6 -6
- validator/rules/basic.py +200 -4
- validator/rules/comparison.py +12 -12
- validator/rules/conditional.py +71 -238
- validator/rules/date.py +7 -7
- validator/rules/files.py +5 -5
- validator/rules/format.py +8 -8
- validator/rules/string.py +8 -15
- validator/rules/type.py +10 -3
- validator/rules/utilities.py +78 -153
- validator/services/rule_error_handler.py +221 -24
- safeshield-1.2.1.dist-info/RECORD +0 -31
- {safeshield-1.2.1.dist-info → safeshield-1.3.2.dist-info}/LICENSE +0 -0
- {safeshield-1.2.1.dist-info → safeshield-1.3.2.dist-info}/WHEEL +0 -0
- {safeshield-1.2.1.dist-info → safeshield-1.3.2.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: safeshield
|
|
3
|
-
Version: 1.2
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: Library for Help Validation Control
|
|
5
5
|
Home-page: https://github.com/WunsunTarniho/py-guard
|
|
6
6
|
Author: Wunsun Tarniho
|
|
@@ -63,3 +63,9 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
63
63
|
|
|
64
64
|
## v1.2.1 (2024-07-20)
|
|
65
65
|
- Fixed: Bug unique and exist rule.
|
|
66
|
+
|
|
67
|
+
## v1.2.2 (2024-07-20)
|
|
68
|
+
- Fixed: Error when connect use postgres.
|
|
69
|
+
|
|
70
|
+
## v1.3.2 (2024-07-20)
|
|
71
|
+
- Refinement: Groups Inheritance Rule Class.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
validator/__init__.py,sha256=udxDzUicPfxBOAQvzsnl3pHur9VUppKbWMgg35hpiww,244
|
|
2
|
+
validator/exceptions.py,sha256=y2v7CaXmeGFHWcnigtLl4U-sFta_jMiXkGKXWIIVglY,366
|
|
3
|
+
validator/factory.py,sha256=bImQNLhEJg5VTxtHiMYVb2EbHWvimTDqHq-UcA8uolw,812
|
|
4
|
+
validator/core/__init__.py,sha256=ZcqlXJSk03i_CVzmIN-nVe1UOyvwwO5jhbEj7f62Y_o,59
|
|
5
|
+
validator/core/validator.py,sha256=Yaw7__Hf-PuKcXaJ6yaARPEyeofEaoqt5-N3tJZ_jtg,12741
|
|
6
|
+
validator/database/__init__.py,sha256=O-cB6-MhNapJ3iwe5jvifbMfr1dPjXLtEdfNTKIu0hc,171
|
|
7
|
+
validator/database/detector.py,sha256=Vac7oVL26GjU6expGo01-6mgUtXqldr-jirzpYokZBM,9597
|
|
8
|
+
validator/database/manager.py,sha256=XJM_I0WaWfZWV710duAc32p1gtiP2or-MAj75WPw1oM,6478
|
|
9
|
+
validator/rules/__init__.py,sha256=nDE3qoI82qJTCbILLUWkXuwsMOmsDtB1m-3IGIvRfpY,919
|
|
10
|
+
validator/rules/array.py,sha256=3hgD_b2K61fG-xT1UdssHMOdIQKWw5vkdpovNn-kc8E,2835
|
|
11
|
+
validator/rules/base.py,sha256=hrGESfkdvqZrQ1yIK_ftVVOMUuyvNFoz-_qaqUucSy8,3474
|
|
12
|
+
validator/rules/basic.py,sha256=rL9THt3OE5QgtuxGCM_dklNpPKOdmuDP30EiSmvkgP8,9656
|
|
13
|
+
validator/rules/comparison.py,sha256=Tlg3AfjTd-W1RonmhT0PLP_mf4CSyhpl7EsmCEYzEAA,9446
|
|
14
|
+
validator/rules/conditional.py,sha256=M4x9g2LQTXNaNfb7dHRMs6vUseDu3WC1RB41QGiNABQ,5965
|
|
15
|
+
validator/rules/date.py,sha256=sPrq8OgHMyUxRAZch4yt7K3I0lInIIy0dUgRtAkcsMk,5313
|
|
16
|
+
validator/rules/files.py,sha256=eCrarOtaRWv1UBQuv5Y6-CcyHuncyLau8V8Ocpw0NVQ,6565
|
|
17
|
+
validator/rules/format.py,sha256=hyho3Cxcgjz4mqCkO_uvjrJPU1JEOK2IZL7F6Dh9oPg,3784
|
|
18
|
+
validator/rules/string.py,sha256=5NToIDOqBhmUYCg1y2y2zdQ4MMLyJzL0FCTM5XhzAgc,2951
|
|
19
|
+
validator/rules/type.py,sha256=B8YH1T1RBlRNNOmb-5uZKdwBc8Uk1Zj4h4xIzAtJC2M,1883
|
|
20
|
+
validator/rules/utilities.py,sha256=xysxDWoP1hJQyBZhNvdzTyMsFOWsEIxFBvYPljW1coA,5340
|
|
21
|
+
validator/services/__init__.py,sha256=zzKTmqL7v4niFGWHJBfWLqgJ0iTaW_69OzYZN8uInzQ,210
|
|
22
|
+
validator/services/rule_conflict.py,sha256=s1RJNUY5d0WtSMHkrKulBCgJ2BZL2GE0Eu5pdAoiIbM,4943
|
|
23
|
+
validator/services/rule_error_handler.py,sha256=MNgSxnakmc3f_nvGuapRmJ9woKt_-E8Wun39OCTrGB0,10273
|
|
24
|
+
validator/services/rule_preparer.py,sha256=jRcMNjqq2xyZjO64Pim8jWmja5DmTzf0V_uuHG0lJTg,5621
|
|
25
|
+
validator/utils/__init__.py,sha256=Yzo-xv285Be-a233M4duDdYtscuHiuBbPSX_C8yViJI,20
|
|
26
|
+
validator/utils/string.py,sha256=0YACzeEaWNEOR9_7O9A8D1ItIbtWfOJ8IfrzcB8VMYA,515
|
|
27
|
+
safeshield-1.3.2.dist-info/LICENSE,sha256=qugtRyKckyaks6hd2xyxOFSOYM6au1N80pMXuMTPvC4,1090
|
|
28
|
+
safeshield-1.3.2.dist-info/METADATA,sha256=V17d3w6UPE698CGSm83-5C3NOm-lZrCqLJYAy8ozrHM,1984
|
|
29
|
+
safeshield-1.3.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
30
|
+
safeshield-1.3.2.dist-info/top_level.txt,sha256=iUtV3dlHOIiMfLuY4pruY00lFni8JzOkQ3Nh1II19OE,10
|
|
31
|
+
safeshield-1.3.2.dist-info/RECORD,,
|
validator/core/validator.py
CHANGED
|
@@ -221,18 +221,18 @@ class Validator:
|
|
|
221
221
|
try:
|
|
222
222
|
rule.set_validator(self)
|
|
223
223
|
|
|
224
|
-
# Format field name untuk pesan error (otomatis tangkap path aktual)
|
|
225
224
|
display_field = getattr(self, '_current_actual_path', field)
|
|
226
225
|
|
|
227
226
|
if not rule.validate(field, value, getattr(rule, 'params', [])):
|
|
228
227
|
msg = rule.message(display_field, getattr(rule, 'params', []))
|
|
229
|
-
self.error_handler.add_error(display_field, rule.rule_name, msg, value)
|
|
228
|
+
self.error_handler.add_error(display_field, rule.rule_name, getattr(rule, 'params', []), msg, value)
|
|
229
|
+
|
|
230
230
|
return False
|
|
231
231
|
else:
|
|
232
232
|
return True
|
|
233
233
|
except Exception as e:
|
|
234
234
|
display_field = getattr(self, '_current_actual_path', field)
|
|
235
|
-
self.error_handler.add_error(display_field, rule.rule_name, str(e), value)
|
|
235
|
+
self.error_handler.add_error(display_field, rule.rule_name, getattr(rule, 'params', []), str(e), value)
|
|
236
236
|
return False
|
|
237
237
|
|
|
238
238
|
def _get_nested_value(self, path: str) -> Any:
|
validator/database/manager.py
CHANGED
|
@@ -46,7 +46,12 @@ class DatabaseManager:
|
|
|
46
46
|
self.connect()
|
|
47
47
|
cursor = None
|
|
48
48
|
try:
|
|
49
|
-
|
|
49
|
+
if self._connection_params['type'] == 'postgresql':
|
|
50
|
+
from psycopg2.extras import RealDictCursor
|
|
51
|
+
cursor = self.connection.cursor(cursor_factory=RealDictCursor)
|
|
52
|
+
else:
|
|
53
|
+
cursor = self.connection.cursor(dictionary=True)
|
|
54
|
+
|
|
50
55
|
yield cursor
|
|
51
56
|
finally:
|
|
52
57
|
if cursor:
|
validator/rules/array.py
CHANGED
|
@@ -19,8 +19,8 @@ class ArrayRule(ValidationRule):
|
|
|
19
19
|
|
|
20
20
|
def message(self, field: str, params: List[str]) -> str:
|
|
21
21
|
if params:
|
|
22
|
-
return f"The
|
|
23
|
-
return f"The
|
|
22
|
+
return f"The :attribute must contain the keys: {', '.join(self._missing_keys)}."
|
|
23
|
+
return f"The :attribute must be an array."
|
|
24
24
|
|
|
25
25
|
class ContainsRule(ValidationRule):
|
|
26
26
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -44,7 +44,7 @@ class ContainsRule(ValidationRule):
|
|
|
44
44
|
return False
|
|
45
45
|
|
|
46
46
|
def message(self, field: str, params: List[str]) -> str:
|
|
47
|
-
return f"The :
|
|
47
|
+
return f"The :attribute must contain {params[0]}"
|
|
48
48
|
|
|
49
49
|
class DistinctRule(ValidationRule):
|
|
50
50
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -54,7 +54,7 @@ class DistinctRule(ValidationRule):
|
|
|
54
54
|
return len(value) == len(set(value))
|
|
55
55
|
|
|
56
56
|
def message(self, field: str, params: List[str]) -> str:
|
|
57
|
-
return f"The :
|
|
57
|
+
return f"The :attribute must contain unique values"
|
|
58
58
|
|
|
59
59
|
class InArrayRule(ValidationRule):
|
|
60
60
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -64,7 +64,7 @@ class InArrayRule(ValidationRule):
|
|
|
64
64
|
return str(value) in params
|
|
65
65
|
|
|
66
66
|
def message(self, field: str, params: List[str]) -> str:
|
|
67
|
-
return f"The :
|
|
67
|
+
return f"The :attribute must be one of: {', '.join(params)}"
|
|
68
68
|
|
|
69
69
|
class InArrayKeysRule(ValidationRule):
|
|
70
70
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -74,4 +74,4 @@ class InArrayKeysRule(ValidationRule):
|
|
|
74
74
|
return any(key in value for key in params)
|
|
75
75
|
|
|
76
76
|
def message(self, field: str, params: List[str]) -> str:
|
|
77
|
-
return f"The :
|
|
77
|
+
return f"The :attribute must contain at least one of these keys: {', '.join(params)}"
|
validator/rules/basic.py
CHANGED
|
@@ -5,33 +5,103 @@ from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
|
|
|
5
5
|
# BASIC VALIDATION RULES
|
|
6
6
|
# =============================================
|
|
7
7
|
|
|
8
|
+
class AnyOfRule(ValidationRule):
|
|
9
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
10
|
+
if not params:
|
|
11
|
+
return False
|
|
12
|
+
return any(self.get_field_value(param, param) == value for param in params)
|
|
13
|
+
|
|
14
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
15
|
+
return f"The :attribute must be one of: {', '.join(params)}"
|
|
16
|
+
|
|
17
|
+
class BailRule(ValidationRule):
|
|
18
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
19
|
+
self.validator._stop_on_first_failure = True
|
|
20
|
+
return True
|
|
21
|
+
|
|
22
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
23
|
+
return ""
|
|
24
|
+
|
|
8
25
|
class RequiredRule(ValidationRule):
|
|
9
26
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
10
27
|
return not self.is_empty(value)
|
|
11
28
|
|
|
12
29
|
def message(self, field: str, params: List[str]) -> str:
|
|
13
|
-
return f"The :
|
|
30
|
+
return f"The :attribute field is required."
|
|
14
31
|
|
|
32
|
+
class ProhibitedRule(ValidationRule):
|
|
33
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
34
|
+
return self.is_empty(value)
|
|
35
|
+
|
|
36
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
37
|
+
return "The :attribute field is must be empty."
|
|
38
|
+
|
|
15
39
|
class NullableRule(ValidationRule):
|
|
16
40
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
17
41
|
return True
|
|
18
42
|
|
|
19
43
|
def message(self, field: str, params: List[str]) -> str:
|
|
20
|
-
return f"The :
|
|
44
|
+
return f"The :attribute may be null."
|
|
21
45
|
|
|
22
46
|
class FilledRule(ValidationRule):
|
|
23
47
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
24
48
|
return value not in ('', None)
|
|
25
49
|
|
|
26
50
|
def message(self, field: str, params: List[str]) -> str:
|
|
27
|
-
return f"The :
|
|
51
|
+
return f"The :attribute field must have a value."
|
|
28
52
|
|
|
29
53
|
class PresentRule(ValidationRule):
|
|
30
54
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
31
55
|
return field in self.validator.data
|
|
32
56
|
|
|
33
57
|
def message(self, field: str, params: List[str]) -> str:
|
|
34
|
-
return f"The :
|
|
58
|
+
return f"The :attribute field must be present."
|
|
59
|
+
|
|
60
|
+
class MissingRule(ValidationRule):
|
|
61
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
62
|
+
return value is None
|
|
63
|
+
|
|
64
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
65
|
+
return f"The :attribute field must be missing."
|
|
66
|
+
|
|
67
|
+
class ProhibitsRule(ValidationRule):
|
|
68
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
69
|
+
if not params or value is None:
|
|
70
|
+
return True
|
|
71
|
+
return all(self.get_field_value(param, param) in (None, 'None') for param in params)
|
|
72
|
+
|
|
73
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
74
|
+
return f"When :attribute is present, {', '.join(params)} must be absent."
|
|
75
|
+
|
|
76
|
+
class AcceptedRule(ValidationRule):
|
|
77
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
78
|
+
value = self.get_field_value(value, value)
|
|
79
|
+
|
|
80
|
+
if isinstance(value, str):
|
|
81
|
+
return value.lower() in ['yes', 'on', '1', 1, True, 'true', 'True']
|
|
82
|
+
if isinstance(value, int):
|
|
83
|
+
return value == 1
|
|
84
|
+
if isinstance(value, bool):
|
|
85
|
+
return value
|
|
86
|
+
return False
|
|
87
|
+
|
|
88
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
89
|
+
return f"The :attribute must be accepted."
|
|
90
|
+
|
|
91
|
+
class DeclinedRule(ValidationRule):
|
|
92
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
93
|
+
value = self.get_field_value(value, value)
|
|
94
|
+
|
|
95
|
+
if isinstance(value, str):
|
|
96
|
+
return value.lower() in ['no', 'off', '0', 0, False, 'false', 'False']
|
|
97
|
+
if isinstance(value, int):
|
|
98
|
+
return value == 0
|
|
99
|
+
if isinstance(value, bool):
|
|
100
|
+
return not value
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
104
|
+
return f"The :attribute must be declined."
|
|
35
105
|
|
|
36
106
|
class SometimesRule(ValidationRule):
|
|
37
107
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -39,3 +109,129 @@ class SometimesRule(ValidationRule):
|
|
|
39
109
|
|
|
40
110
|
def message(self, field: str, params: List[str]) -> str:
|
|
41
111
|
return ""
|
|
112
|
+
|
|
113
|
+
class ExcludeRule(ValidationRule):
|
|
114
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
115
|
+
self.validator._is_exclude = True
|
|
116
|
+
|
|
117
|
+
return True
|
|
118
|
+
|
|
119
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
120
|
+
return ""
|
|
121
|
+
|
|
122
|
+
class UniqueRule(ValidationRule):
|
|
123
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
124
|
+
if not params or not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
table = params[0]
|
|
128
|
+
column = field if len(params) == 1 else params[1]
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
ignore_id = None
|
|
132
|
+
if len(params) > 2 and params[2].startswith('ignore:'):
|
|
133
|
+
ignore_field = params[2].split(':')[1]
|
|
134
|
+
ignore_id = self.get_field_value(ignore_field)
|
|
135
|
+
return self.validator.db_manager.is_unique(table, column, value, ignore_id)
|
|
136
|
+
except Exception as e:
|
|
137
|
+
print(f"Database error in UniqueRule: {e}")
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
141
|
+
return f"The :attribute has already been taken."
|
|
142
|
+
|
|
143
|
+
class ExistsRule(ValidationRule):
|
|
144
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
145
|
+
if not params or not hasattr(self.validator, 'db_manager') or not self.validator.db_manager:
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
table = params[0]
|
|
149
|
+
column = field if len(params) == 1 else params[1]
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
return self.validator.db_manager.exists(table, column, value)
|
|
153
|
+
except Exception as e:
|
|
154
|
+
print(f"Database error in ExistsRule: {e}")
|
|
155
|
+
return False
|
|
156
|
+
|
|
157
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
158
|
+
return f"The selected :attribute is invalid."
|
|
159
|
+
|
|
160
|
+
class ConfirmedRule(ValidationRule):
|
|
161
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
162
|
+
confirmation_field = f"{field}_confirmation"
|
|
163
|
+
|
|
164
|
+
return value == self.get_field_value(confirmation_field, '')
|
|
165
|
+
|
|
166
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
167
|
+
return f"The :attribute confirmation does not match."
|
|
168
|
+
|
|
169
|
+
class SameRule(ValidationRule):
|
|
170
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
171
|
+
if not params:
|
|
172
|
+
return False
|
|
173
|
+
return value == self.get_field_value(params[0])
|
|
174
|
+
|
|
175
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
176
|
+
return f"The :attribute and {params[0]} must match."
|
|
177
|
+
|
|
178
|
+
class DifferentRule(ValidationRule):
|
|
179
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
180
|
+
if not params:
|
|
181
|
+
return False
|
|
182
|
+
return value != self.get_field_value(params[0])
|
|
183
|
+
|
|
184
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
185
|
+
return f"The :attribute and {params[0]} must be different."
|
|
186
|
+
|
|
187
|
+
class RegexRule(ValidationRule):
|
|
188
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
189
|
+
if not params or not isinstance(value, str):
|
|
190
|
+
return False
|
|
191
|
+
try:
|
|
192
|
+
return bool(re.fullmatch(params[0], value))
|
|
193
|
+
except re.error:
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
197
|
+
return f"The :attribute format is invalid."
|
|
198
|
+
|
|
199
|
+
class NotRegexRule(ValidationRule):
|
|
200
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
201
|
+
if not params or not isinstance(value, str):
|
|
202
|
+
return True
|
|
203
|
+
print(not bool(re.search(params[0], value)))
|
|
204
|
+
try:
|
|
205
|
+
return not bool(re.search(params[0], value))
|
|
206
|
+
except re.error:
|
|
207
|
+
return True
|
|
208
|
+
|
|
209
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
210
|
+
return f"The :attribute format is invalid."
|
|
211
|
+
|
|
212
|
+
class InRule(ValidationRule):
|
|
213
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
214
|
+
allowed_values = self._parse_option_values(field, params)
|
|
215
|
+
return (str(value) in allowed_values or value in allowed_values)
|
|
216
|
+
|
|
217
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
218
|
+
allowed_values = self._parse_option_values(field, params)
|
|
219
|
+
return f"The selected :attribute must be in : {', '.join(map(str, allowed_values))}"
|
|
220
|
+
|
|
221
|
+
class NotInRule(ValidationRule):
|
|
222
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
223
|
+
not_allowed_values = self._parse_option_values(field, params)
|
|
224
|
+
return str(value) not in not_allowed_values
|
|
225
|
+
|
|
226
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
227
|
+
not_allowed_values = self._parse_option_values(field, params)
|
|
228
|
+
return f"The selected :attribute must be not in : {', '.join(map(str, not_allowed_values))}"
|
|
229
|
+
|
|
230
|
+
class EnumRule(ValidationRule):
|
|
231
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
232
|
+
allowed_values = self._parse_option_values(field, params)
|
|
233
|
+
return (str(value) in allowed_values or value in allowed_values)
|
|
234
|
+
|
|
235
|
+
def message(self, field: str, params: List[str]) -> str:
|
|
236
|
+
allowed_values = self._parse_option_values(field, params)
|
|
237
|
+
return f"The :attribute must be one of: {', '.join(map(str, allowed_values))}"
|
validator/rules/comparison.py
CHANGED
|
@@ -27,7 +27,7 @@ class MinRule(ValidationRule):
|
|
|
27
27
|
return False
|
|
28
28
|
|
|
29
29
|
def message(self, field: str, params: List[str]) -> str:
|
|
30
|
-
return f"The :
|
|
30
|
+
return f"The :attribute must be at least {params[0]}."
|
|
31
31
|
|
|
32
32
|
class MaxRule(ValidationRule):
|
|
33
33
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -85,13 +85,13 @@ class MaxRule(ValidationRule):
|
|
|
85
85
|
def message(self, field: str, params: List[str]) -> str:
|
|
86
86
|
value = self.get_field_value(field)
|
|
87
87
|
if value is None:
|
|
88
|
-
return f"The
|
|
88
|
+
return f"The :attribute must not exceed {params[0]}"
|
|
89
89
|
|
|
90
90
|
# Check all possible file size attributes
|
|
91
91
|
file_attrs = ['content_length', 'size', 'fileno']
|
|
92
92
|
if any(hasattr(value, attr) for attr in file_attrs):
|
|
93
|
-
return f"File
|
|
94
|
-
return f"The
|
|
93
|
+
return f"File :attribute must not exceed {params[0]} bytes"
|
|
94
|
+
return f"The :attribute must not exceed {params[0]}"
|
|
95
95
|
|
|
96
96
|
class BetweenRule(ValidationRule):
|
|
97
97
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -136,8 +136,8 @@ class BetweenRule(ValidationRule):
|
|
|
136
136
|
def message(self, field: str, params: List[str]) -> str:
|
|
137
137
|
value = self.get_field_value(field)
|
|
138
138
|
if hasattr(value, 'content_length') or hasattr(value, 'size'):
|
|
139
|
-
return f"File
|
|
140
|
-
return f"The
|
|
139
|
+
return f"File :attribute must be between {params[0]} and {params[1]} bytes"
|
|
140
|
+
return f"The :attribute must be between {params[0]} and {params[1]}"
|
|
141
141
|
|
|
142
142
|
class SizeRule(ValidationRule):
|
|
143
143
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -182,14 +182,14 @@ class SizeRule(ValidationRule):
|
|
|
182
182
|
def message(self, field: str, params: List[str]) -> str:
|
|
183
183
|
value = self.get_field_value(field)
|
|
184
184
|
if value is None:
|
|
185
|
-
return f"The
|
|
185
|
+
return f"The :attribute must be exactly {params[0]}"
|
|
186
186
|
|
|
187
187
|
# Check for file attributes
|
|
188
188
|
file_attrs = ['content_length', 'size', 'fileno']
|
|
189
189
|
if any(hasattr(value, attr) for attr in file_attrs):
|
|
190
|
-
return f"File
|
|
190
|
+
return f"File :attribute must be exactly {params[0]} bytes"
|
|
191
191
|
|
|
192
|
-
return f"The
|
|
192
|
+
return f"The :attribute must be exactly {params[0]}"
|
|
193
193
|
|
|
194
194
|
class DigitsRule(ValidationRule):
|
|
195
195
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -204,7 +204,7 @@ class DigitsRule(ValidationRule):
|
|
|
204
204
|
return value.isdigit() and len(value) == digits
|
|
205
205
|
|
|
206
206
|
def message(self, field: str, params: List[str]) -> str:
|
|
207
|
-
return f"The :
|
|
207
|
+
return f"The :attribute must be {params[0]} digits."
|
|
208
208
|
|
|
209
209
|
class DigitsBetweenRule(ValidationRule):
|
|
210
210
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -220,7 +220,7 @@ class DigitsBetweenRule(ValidationRule):
|
|
|
220
220
|
return value.isdigit() and min_digits <= len(value) <= max_digits
|
|
221
221
|
|
|
222
222
|
def message(self, field: str, params: List[str]) -> str:
|
|
223
|
-
return f"The :
|
|
223
|
+
return f"The :attribute must be between {params[0]} and {params[1]} digits."
|
|
224
224
|
|
|
225
225
|
class MultipleOfRule(ValidationRule):
|
|
226
226
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
@@ -237,4 +237,4 @@ class MultipleOfRule(ValidationRule):
|
|
|
237
237
|
return False
|
|
238
238
|
|
|
239
239
|
def message(self, field: str, params: List[str]) -> str:
|
|
240
|
-
return f"The :
|
|
240
|
+
return f"The :attribute must be a multiple of {params[0]}."
|