safeshield 1.2.2__py3-none-any.whl → 1.4.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.2.dist-info → safeshield-1.4.2.dist-info}/METADATA +9 -1
- safeshield-1.4.2.dist-info/RECORD +31 -0
- validator/core/validator.py +10 -10
- validator/factory.py +4 -4
- validator/rules/__init__.py +6 -8
- validator/rules/array.py +27 -34
- validator/rules/base.py +32 -8
- validator/rules/basic.py +105 -10
- validator/rules/boolean.py +157 -0
- validator/rules/comparison.py +130 -40
- validator/rules/date.py +36 -20
- validator/rules/files.py +179 -67
- validator/rules/format.py +122 -31
- validator/rules/numeric.py +188 -0
- validator/rules/string.py +71 -19
- validator/rules/utilities.py +233 -133
- validator/services/rule_conflict.py +2 -2
- validator/services/rule_error_handler.py +221 -24
- validator/services/rule_preparer.py +12 -25
- safeshield-1.2.2.dist-info/RECORD +0 -31
- validator/rules/conditional.py +0 -332
- validator/rules/type.py +0 -42
- {safeshield-1.2.2.dist-info → safeshield-1.4.2.dist-info}/LICENSE +0 -0
- {safeshield-1.2.2.dist-info → safeshield-1.4.2.dist-info}/WHEEL +0 -0
- {safeshield-1.2.2.dist-info → safeshield-1.4.2.dist-info}/top_level.txt +0 -0
validator/rules/utilities.py
CHANGED
|
@@ -1,41 +1,46 @@
|
|
|
1
|
-
from .base import
|
|
1
|
+
from .base import Rule
|
|
2
2
|
from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
|
|
3
|
+
from .basic import *
|
|
4
|
+
from .boolean import AcceptedRule, DeclinedRule
|
|
3
5
|
|
|
4
|
-
class
|
|
6
|
+
class RequiredIfRule(RequiredRule):
|
|
5
7
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
6
|
-
if
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
if len(params) == 1 and callable(params[0]):
|
|
9
|
+
condition_met = params[0](self.validator.data)
|
|
10
|
+
elif len(params) == 1 and isinstance(params[0], bool):
|
|
11
|
+
condition_met = params[0]
|
|
12
|
+
else:
|
|
13
|
+
conditions = list(zip(params[::2], params[1::2]))
|
|
14
|
+
|
|
15
|
+
condition_met = any(
|
|
16
|
+
str(self.get_field_value(field, '')) == str(expected_value)
|
|
17
|
+
for field, expected_value in conditions
|
|
18
|
+
if field and expected_value is not None
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if condition_met:
|
|
22
|
+
return super().validate(field, value, params)
|
|
23
|
+
|
|
24
|
+
return True
|
|
16
25
|
|
|
17
|
-
|
|
18
|
-
return f"The :name field is excluded."
|
|
19
|
-
|
|
20
|
-
class ExcludeIfRule(ValidationRule):
|
|
26
|
+
class RequiredUnlessRule(RequiredRule):
|
|
21
27
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
28
|
+
if len(params) < 2:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
other_field, other_value = params[0], params[1]
|
|
32
|
+
actual_value = self.get_field_value(other_field, '')
|
|
28
33
|
|
|
29
|
-
if
|
|
30
|
-
|
|
34
|
+
if actual_value == other_value:
|
|
35
|
+
return True
|
|
31
36
|
|
|
32
|
-
return
|
|
37
|
+
return super().validate(field, value, params)
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
return f"The :name field is excluded when {params[0]} is {params[1]}."
|
|
36
|
-
|
|
37
|
-
class ExcludeUnlessRule(ValidationRule):
|
|
39
|
+
class RequiredAllIfRule(RequiredRule):
|
|
38
40
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
41
|
+
if len(params) < 2:
|
|
42
|
+
return False
|
|
43
|
+
|
|
39
44
|
conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
|
|
40
45
|
|
|
41
46
|
all_conditions_met = all(
|
|
@@ -44,170 +49,265 @@ class ExcludeUnlessRule(ValidationRule):
|
|
|
44
49
|
)
|
|
45
50
|
|
|
46
51
|
if not all_conditions_met:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return True
|
|
52
|
+
return True
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class ExcludeWithRule(ValidationRule):
|
|
54
|
+
return super().validate(field, value, params)
|
|
55
|
+
|
|
56
|
+
class RequiredWithRule(RequiredRule):
|
|
55
57
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
56
|
-
if
|
|
57
|
-
|
|
58
|
+
if not params:
|
|
59
|
+
return False
|
|
58
60
|
|
|
61
|
+
if any(f in self.validator.data for f in params):
|
|
62
|
+
return super().validate(field, value, params)
|
|
59
63
|
return True
|
|
60
|
-
|
|
61
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
62
|
-
return f"The :name field is excluded when any of {', '.join(params)} is present."
|
|
63
64
|
|
|
64
|
-
class
|
|
65
|
+
class RequiredWithAllRule(RequiredRule):
|
|
65
66
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
66
|
-
if
|
|
67
|
-
|
|
67
|
+
if not params:
|
|
68
|
+
return False
|
|
68
69
|
|
|
70
|
+
if all(f in self.validator.data for f in params):
|
|
71
|
+
return not self.is_empty(value)
|
|
69
72
|
return True
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
return f"The :name field is excluded when any of {', '.join(params)} is missing."
|
|
73
|
-
|
|
74
|
-
class MissingRule(ValidationRule):
|
|
75
|
-
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
76
|
-
return value is None
|
|
77
|
-
|
|
78
|
-
def message(self, field: str, params: List[str]) -> str:
|
|
79
|
-
return f"The :name field must be missing."
|
|
80
|
-
|
|
81
|
-
class MissingIfRule(ValidationRule):
|
|
74
|
+
class RequiredWithoutRule(RequiredRule):
|
|
82
75
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
83
|
-
if
|
|
76
|
+
if not params:
|
|
84
77
|
return False
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
|
|
79
|
+
if any(f not in self.validator.data for f in params):
|
|
80
|
+
return super().validate(field, value, params)
|
|
81
|
+
return True
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
return f"The :name field must be missing when {params[0]} is {params[1]}."
|
|
90
|
-
|
|
91
|
-
class MissingUnlessRule(ValidationRule):
|
|
83
|
+
class RequiredWithoutAllRule(RequiredRule):
|
|
92
84
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
93
|
-
if
|
|
85
|
+
if not params:
|
|
94
86
|
return False
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
|
|
88
|
+
if all(f not in self.validator.data for f in params):
|
|
89
|
+
return super().validate(field, value, params)
|
|
90
|
+
return True
|
|
97
91
|
|
|
98
|
-
|
|
99
|
-
return f"The :name field must be missing unless {params[0]} is {params[1]}."
|
|
100
|
-
|
|
101
|
-
class MissingWithRule(ValidationRule):
|
|
92
|
+
class RequiredIfAcceptedRule(RequiredRule, AcceptedRule):
|
|
102
93
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
103
94
|
if not params:
|
|
104
95
|
return False
|
|
105
|
-
|
|
96
|
+
|
|
97
|
+
if AcceptedRule.validate(self, field, params[0], params):
|
|
98
|
+
return super().validate(field, value, params)
|
|
99
|
+
|
|
100
|
+
return True
|
|
106
101
|
|
|
107
|
-
|
|
108
|
-
return f"The :name field must be missing when any of {', '.join(params)} is present."
|
|
109
|
-
|
|
110
|
-
class MissingWithAllRule(ValidationRule):
|
|
102
|
+
class RequiredIfDeclinedRule(RequiredRule, DeclinedRule):
|
|
111
103
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
112
104
|
if not params:
|
|
113
105
|
return False
|
|
114
|
-
|
|
106
|
+
|
|
107
|
+
if DeclinedRule.validate(self, field, params[0], params):
|
|
108
|
+
return super().validate(field, value, params)
|
|
109
|
+
|
|
110
|
+
return True
|
|
115
111
|
|
|
116
|
-
|
|
117
|
-
return f"The :name field must be missing when all of {', '.join(params)} are present."
|
|
118
|
-
|
|
119
|
-
class PresentIfRule(ValidationRule):
|
|
112
|
+
class RequiredArrayKeysRule(Rule):
|
|
120
113
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
121
|
-
if
|
|
114
|
+
if not isinstance(value, dict) or not params:
|
|
122
115
|
return False
|
|
123
|
-
|
|
124
|
-
return value is not None if self.get_field_value(other_field, None) == other_value else True
|
|
116
|
+
return all(key in value for key in params)
|
|
125
117
|
|
|
126
118
|
def message(self, field: str, params: List[str]) -> str:
|
|
127
|
-
return f"The :
|
|
128
|
-
|
|
129
|
-
class
|
|
119
|
+
return f"The :attribute must contain all required keys: {', '.join(params)}"
|
|
120
|
+
|
|
121
|
+
class ProhibitedIfRule(ProhibitedRule):
|
|
122
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
123
|
+
if len(params) == 1 and callable(params[0]):
|
|
124
|
+
condition_met = params[0](self.validator.data)
|
|
125
|
+
elif len(params) == 1 and isinstance(params[0], bool):
|
|
126
|
+
condition_met = params[0]
|
|
127
|
+
else:
|
|
128
|
+
other_field, other_value = params[0], params[1]
|
|
129
|
+
actual_value = self.get_field_value(other_field, '')
|
|
130
|
+
|
|
131
|
+
condition_met = actual_value == other_value
|
|
132
|
+
|
|
133
|
+
if condition_met:
|
|
134
|
+
return super().validate(field, value, params)
|
|
135
|
+
return True
|
|
136
|
+
|
|
137
|
+
class ProhibitedUnlessRule(ProhibitedRule):
|
|
130
138
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
131
139
|
if len(params) < 2:
|
|
132
140
|
return False
|
|
141
|
+
|
|
133
142
|
other_field, other_value = params[0], params[1]
|
|
134
|
-
|
|
143
|
+
actual_value = self.get_field_value(other_field, '')
|
|
144
|
+
|
|
145
|
+
if actual_value == other_value:
|
|
146
|
+
return True
|
|
147
|
+
|
|
148
|
+
return super().validate(field, value, params)
|
|
135
149
|
|
|
136
|
-
|
|
137
|
-
return f"The :name field must be present unless {params[0]} is {params[1]}."
|
|
138
|
-
|
|
139
|
-
class PresentWithRule(ValidationRule):
|
|
150
|
+
class ProhibitedIfAcceptedRule(ProhibitedRule, AcceptedRule):
|
|
140
151
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
141
152
|
if not params:
|
|
142
153
|
return False
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return
|
|
154
|
+
|
|
155
|
+
if AcceptedRule.validate(self, field, params[0], params):
|
|
156
|
+
return super().validate(field, value, params)
|
|
157
|
+
return True
|
|
147
158
|
|
|
148
|
-
class
|
|
159
|
+
class ProhibitedIfDeclinedRule(ProhibitedRule, DeclinedRule):
|
|
149
160
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
150
161
|
if not params:
|
|
151
162
|
return False
|
|
152
|
-
|
|
163
|
+
|
|
164
|
+
if DeclinedRule.validate(self, field, params[0], params):
|
|
165
|
+
return super().validate(field, value, params)
|
|
166
|
+
|
|
167
|
+
return True
|
|
153
168
|
|
|
154
|
-
|
|
155
|
-
return f"The :name field must be present when all of {', '.join(params)} are present."
|
|
156
|
-
|
|
157
|
-
class ProhibitedIfAcceptedRule(ValidationRule):
|
|
169
|
+
class PresentIfRule(PresentRule):
|
|
158
170
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
159
|
-
|
|
171
|
+
condition_met = False
|
|
172
|
+
|
|
173
|
+
if len(params) == 1 and callable(params[0]):
|
|
174
|
+
condition_met = params[0](self.validator.data)
|
|
175
|
+
elif len(params) == 1 and isinstance(params[0], bool):
|
|
176
|
+
condition_met = params[0]
|
|
177
|
+
else:
|
|
178
|
+
conditions = list(zip(params[::2], params[1::2]))
|
|
179
|
+
for other_field, expected_value in conditions:
|
|
180
|
+
if self.get_field_value(other_field, None) == expected_value:
|
|
181
|
+
condition_met = True
|
|
182
|
+
break
|
|
183
|
+
|
|
184
|
+
if condition_met:
|
|
185
|
+
return super().validate(field, value, params)
|
|
186
|
+
|
|
187
|
+
return True
|
|
188
|
+
|
|
189
|
+
class PresentUnlessRule(PresentRule):
|
|
190
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
191
|
+
if len(params) < 2:
|
|
160
192
|
return False
|
|
161
|
-
other_field = params[0]
|
|
162
|
-
|
|
193
|
+
other_field, other_value = params[0], params[1]
|
|
194
|
+
|
|
195
|
+
if self.get_field_value(other_field, None) != other_value:
|
|
196
|
+
return super().validate(field, value, params)
|
|
197
|
+
|
|
198
|
+
return True
|
|
163
199
|
|
|
164
|
-
|
|
165
|
-
return f"The :name field is prohibited when {params[0]} is accepted."
|
|
166
|
-
|
|
167
|
-
class ProhibitedIfDeclinedRule(ValidationRule):
|
|
200
|
+
class PresentWithRule(PresentRule):
|
|
168
201
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
169
202
|
if not params:
|
|
170
203
|
return False
|
|
171
|
-
|
|
172
|
-
|
|
204
|
+
if any(self.get_field_value(param, None) is not None for param in params):
|
|
205
|
+
return super().validate(field, value, params)
|
|
206
|
+
|
|
207
|
+
return True
|
|
173
208
|
|
|
174
|
-
|
|
175
|
-
|
|
209
|
+
class PresentWithAllRule(PresentRule):
|
|
210
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
211
|
+
if not params:
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
if all(self.get_field_value(param, None) is not None for param in params):
|
|
215
|
+
return super().validate(field, value, params)
|
|
176
216
|
|
|
177
|
-
class
|
|
217
|
+
class MissingIfRule(MissingRule):
|
|
178
218
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
219
|
+
condition_met = False
|
|
220
|
+
|
|
221
|
+
if len(params) == 1 and callable(params[0]):
|
|
222
|
+
condition_met = params[0](self.validator.data)
|
|
223
|
+
elif len(params) == 1 and isinstance(params[0], bool):
|
|
224
|
+
condition_met = params[0]
|
|
225
|
+
else:
|
|
226
|
+
conditions = list(zip(params[::2], params[1::2]))
|
|
227
|
+
for other_field, expected_value in conditions:
|
|
228
|
+
if self.get_field_value(other_field, None) == expected_value:
|
|
229
|
+
condition_met = True
|
|
230
|
+
break
|
|
231
|
+
|
|
232
|
+
if condition_met:
|
|
233
|
+
return super().validate(field, value, params)
|
|
234
|
+
|
|
235
|
+
return True
|
|
182
236
|
|
|
183
|
-
|
|
184
|
-
|
|
237
|
+
class MissingUnlessRule(MissingRule):
|
|
238
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
239
|
+
if len(params) < 2:
|
|
240
|
+
return False
|
|
241
|
+
other_field, other_value = params[0], params[1]
|
|
242
|
+
if self.get_field_value(other_field, None) != other_value:
|
|
243
|
+
return super().validate(field, value, params)
|
|
185
244
|
|
|
186
|
-
|
|
245
|
+
return True
|
|
246
|
+
|
|
247
|
+
class MissingWithRule(MissingRule):
|
|
187
248
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
188
249
|
if not params:
|
|
189
250
|
return False
|
|
190
|
-
|
|
191
|
-
|
|
251
|
+
|
|
252
|
+
if any(self.get_field_value(param, None) is not None for param in params):
|
|
253
|
+
return super().validate(field, value, params)
|
|
254
|
+
|
|
255
|
+
return True
|
|
192
256
|
|
|
193
|
-
|
|
194
|
-
return f"The :name field is required when {params[0]} is accepted."
|
|
195
|
-
|
|
196
|
-
class RequiredIfDeclinedRule(ValidationRule):
|
|
257
|
+
class MissingWithAllRule(MissingRule):
|
|
197
258
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
198
259
|
if not params:
|
|
199
260
|
return False
|
|
200
|
-
|
|
201
|
-
|
|
261
|
+
|
|
262
|
+
if all(self.get_field_value(param, None) is not None for param in params):
|
|
263
|
+
return super().validate(field, value, params)
|
|
264
|
+
|
|
265
|
+
return True
|
|
202
266
|
|
|
267
|
+
class ExcludeIfRule(ExcludeRule):
|
|
268
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
269
|
+
if len(params) == 1 and callable(params[0]):
|
|
270
|
+
condition_met = params[0](self.validator.data)
|
|
271
|
+
elif len(params) == 1 and isinstance(params[0], bool):
|
|
272
|
+
condition_met = params[0]
|
|
273
|
+
else:
|
|
274
|
+
conditions = list(zip(params[::2], params[1::2]))
|
|
275
|
+
condition_met = all(
|
|
276
|
+
str(self.get_field_value(f)) == str(v)
|
|
277
|
+
for f, v in conditions
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
if condition_met:
|
|
281
|
+
return super().validate(field, value, params)
|
|
282
|
+
return True
|
|
283
|
+
|
|
284
|
+
class ExcludeUnlessRule(ExcludeRule):
|
|
285
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
286
|
+
conditions = [(f.strip(), v.strip()) for f, v in zip(params[::2], params[1::2])]
|
|
287
|
+
|
|
288
|
+
all_conditions_met = all(
|
|
289
|
+
self.get_field_value(f) == v
|
|
290
|
+
for f, v in conditions
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
if not all_conditions_met:
|
|
294
|
+
return super().validate(field, value, params)
|
|
295
|
+
|
|
296
|
+
return True
|
|
297
|
+
|
|
203
298
|
def message(self, field: str, params: List[str]) -> str:
|
|
204
|
-
return f"The :
|
|
299
|
+
return f"The :attribute field is excluded unless {params[0]} is {params[1]}."
|
|
205
300
|
|
|
206
|
-
class
|
|
301
|
+
class ExcludeWithRule(ExcludeRule):
|
|
207
302
|
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
208
|
-
if not
|
|
209
|
-
return
|
|
210
|
-
|
|
303
|
+
if any(not self.is_empty(self.get_field_value(param, None)) for param in params):
|
|
304
|
+
return super().validate(field, value, params)
|
|
305
|
+
|
|
306
|
+
return True
|
|
211
307
|
|
|
212
|
-
|
|
213
|
-
|
|
308
|
+
class ExcludeWithoutRule(ExcludeRule):
|
|
309
|
+
def validate(self, field: str, value: Any, params: List[str]) -> bool:
|
|
310
|
+
if any(self.is_empty(self.get_field_value(param, None)) for param in params):
|
|
311
|
+
return super().validate(field, value, params)
|
|
312
|
+
|
|
313
|
+
return True
|
|
@@ -58,11 +58,11 @@ class RuleConflictChecker:
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
@classmethod
|
|
61
|
-
def check_conflicts(cls, rules: List['
|
|
61
|
+
def check_conflicts(cls, rules: List['Rule']) -> None:
|
|
62
62
|
"""Main method untuk mengecek semua jenis konflik.
|
|
63
63
|
|
|
64
64
|
Args:
|
|
65
|
-
rules: List of
|
|
65
|
+
rules: List of Rule objects to check
|
|
66
66
|
|
|
67
67
|
Raises:
|
|
68
68
|
ValueError: Untuk konflik kritis
|