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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: safeshield
3
- Version: 1.3.2
3
+ Version: 1.4.3
4
4
  Summary: Library for Help Validation Control
5
5
  Home-page: https://github.com/WunsunTarniho/py-guard
6
6
  Author: Wunsun Tarniho
@@ -24,6 +24,8 @@ Requires-Dist: python-dateutil==2.9.0.post0
24
24
  Requires-Dist: setuptools==63.2.0
25
25
  Requires-Dist: SQLAlchemy==2.0.41
26
26
  Requires-Dist: Werkzeug==1.0.1
27
+ Requires-Dist: dnspython==2.4.2
28
+ Requires-Dist: idna==3.4
27
29
 
28
30
  ## License
29
31
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
@@ -69,3 +71,9 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
69
71
 
70
72
  ## v1.3.2 (2024-07-20)
71
73
  - Refinement: Groups Inheritance Rule Class.
74
+
75
+ ## v1.4.2 (2024-07-20)
76
+ - Feature: Rule can accept function as argument, Rule Chaning
77
+
78
+ ## v1.4.3 (2024-07-20)
79
+ - Fixed: Error when validation failed
@@ -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=JruOF0Mumk5PPqendNsO5TN4ZmPEGBNS7Nivly4_oUc,772
4
+ validator/core/__init__.py,sha256=ZcqlXJSk03i_CVzmIN-nVe1UOyvwwO5jhbEj7f62Y_o,59
5
+ validator/core/validator.py,sha256=pbfbTu6OvJiqyNu58OnIZI97a8x2r9T25IrWkBMJKTs,12684
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=z3Vk3R5CRgjeqyDWZxdofD2tBMTgdyYVuFmo1mKOTj4,830
10
+ validator/rules/array.py,sha256=AqVoBR_chSqxPec14Av5KmR9NAByovXDNNu2oeId4-U,2528
11
+ validator/rules/base.py,sha256=PadT5Ko3Zs_yr5EPxOfTw-IdS7uJKhGpaekF1k4tvYk,4359
12
+ validator/rules/basic.py,sha256=GFdffZKW3Dzw7EOeZTyF1Oma59ZMo9zNK4gddkUMMc4,4892
13
+ validator/rules/boolean.py,sha256=vy6huFJ5JidpsoJ0WSvcydiU7a8aYFj225UswggSGAE,5748
14
+ validator/rules/comparison.py,sha256=xkQ0xoqBjVlDSfgwTvruOAnXUmKlNt9kDjTcG5r4cFM,13473
15
+ validator/rules/date.py,sha256=yolYaTIvQTN1LBje5SM8i7EmNzOxV_eUwnOokmqZrMs,5812
16
+ validator/rules/files.py,sha256=c7deO8fEiFNCx4jq1B2sJXhxTqGzTVq4kK2EscSNhKI,10946
17
+ validator/rules/format.py,sha256=Medw57PJwfElxA-DgxiZ5GHqvqPhUCQPFMGCGTDne8w,7070
18
+ validator/rules/numeric.py,sha256=nkYVc8VtrWJ3Kt7JDLPsbg7ZaN3F0zJMnbf8Y5gxNsk,6824
19
+ validator/rules/string.py,sha256=p8ZQfd0XaWIjksg_8ta3f6PEnXlxjRzlSJx1GohZ7yk,5237
20
+ validator/rules/utilities.py,sha256=ns52WbIMTt6Gs85y9kwbTfBjhmX4cfNPwA5Uw6mTaT0,11924
21
+ validator/services/__init__.py,sha256=zzKTmqL7v4niFGWHJBfWLqgJ0iTaW_69OzYZN8uInzQ,210
22
+ validator/services/rule_conflict.py,sha256=JVOgZWIGOviTfcCC69sQ1Bq8nzwtW0UFOx-bbF35uTM,4923
23
+ validator/services/rule_error_handler.py,sha256=0GoBZp12efTY1atu0MKpCXAyDWm_8DYSDrcqfjB6LM8,10415
24
+ validator/services/rule_preparer.py,sha256=4khRjdely_0Z5mxFwf1bKIid076_xDuNh2XBO_fGerE,4706
25
+ validator/utils/__init__.py,sha256=Yzo-xv285Be-a233M4duDdYtscuHiuBbPSX_C8yViJI,20
26
+ validator/utils/string.py,sha256=0YACzeEaWNEOR9_7O9A8D1ItIbtWfOJ8IfrzcB8VMYA,515
27
+ safeshield-1.4.3.dist-info/LICENSE,sha256=qugtRyKckyaks6hd2xyxOFSOYM6au1N80pMXuMTPvC4,1090
28
+ safeshield-1.4.3.dist-info/METADATA,sha256=F0LL5L_zO7VDQfciVKDMKX7ka_D1RBOp5UyjfDsukNY,2197
29
+ safeshield-1.4.3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
30
+ safeshield-1.4.3.dist-info/top_level.txt,sha256=iUtV3dlHOIiMfLuY4pruY00lFni8JzOkQ3Nh1II19OE,10
31
+ safeshield-1.4.3.dist-info/RECORD,,
@@ -2,7 +2,7 @@ from typing import Optional, Dict, Any, List, Tuple, Union
2
2
  from validator.exceptions import ValidationException, RuleNotFoundException
3
3
  from validator.factory import RuleFactory
4
4
  from validator.database import DatabaseManager, DatabaseAutoDetector
5
- from validator.rules import ValidationRule
5
+ from validator.rules import Rule
6
6
  from validator.services.rule_conflict import RuleConflictChecker
7
7
  from validator.services.rule_error_handler import RuleErrorHandler
8
8
  from validator.services.rule_preparer import RulePreparer
@@ -12,7 +12,7 @@ from collections.abc import Mapping
12
12
  class Validator:
13
13
  """Main validation class with proper abstractions"""
14
14
  PRIORITY_RULES = {
15
- 'bail', 'exclude_unless', 'exclude_if', 'exclude_with', 'exclude_without', 'required', 'required_if', 'required_unless',
15
+ 'bail', 'sometimes', 'exclude_unless', 'exclude_if', 'exclude_with', 'exclude_without', 'required', 'required_if', 'required_unless',
16
16
  'required_with', 'required_without'
17
17
  }
18
18
 
@@ -23,7 +23,7 @@ class Validator:
23
23
  str,
24
24
  List[Union[
25
25
  str,
26
- ValidationRule,
26
+ Rule,
27
27
  Tuple[str, Union[
28
28
  str,
29
29
  Union[
@@ -38,7 +38,7 @@ class Validator:
38
38
  ]],
39
39
  Tuple[Union[
40
40
  str,
41
- ValidationRule,
41
+ Rule,
42
42
  Tuple[str, Union[
43
43
  str,
44
44
  Union[
@@ -94,7 +94,7 @@ class Validator:
94
94
  return False
95
95
  return True
96
96
 
97
- def _validate_rules(self, prepared_rules: Dict[str, List[ValidationRule]], priority_only: bool):
97
+ def _validate_rules(self, prepared_rules: Dict[str, List[Rule]], priority_only: bool):
98
98
  validated = []
99
99
  for field_pattern, rules in prepared_rules.items():
100
100
  concrete_paths = self._resolve_wildcard_paths(field_pattern) if '*' in field_pattern else [field_pattern]
@@ -217,7 +217,7 @@ class Validator:
217
217
 
218
218
  return _check(self.data, parts)
219
219
 
220
- def _apply_rule(self, field: str, value: Any, rule: ValidationRule) -> bool:
220
+ def _apply_rule(self, field: str, value: Any, rule: Rule) -> bool:
221
221
  try:
222
222
  rule.set_validator(self)
223
223
 
@@ -275,7 +275,7 @@ class Validator:
275
275
 
276
276
  return result
277
277
 
278
- def add_rule(self, field: str, rules: Union[str, List[Union[str, ValidationRule]], ValidationRule]):
278
+ def add_rule(self, field: str, rules: Union[str, List[Union[str, Rule]], Rule]):
279
279
  """Add new rules to a field"""
280
280
  new_rules = self.rule_preparer._convert_to_rules(rules)
281
281
  existing_rules = self.rule_preparer._convert_to_rules(self._raw_rules.get(field, []))
validator/factory.py CHANGED
@@ -1,20 +1,20 @@
1
1
  # factory.py
2
2
  from typing import Type, Dict, List
3
3
  from validator.rules import all_rules
4
- from validator.rules.base import ValidationRule
4
+ from validator.rules.base import Rule
5
5
 
6
6
  class RuleFactory:
7
- _rules: Dict[str, Type[ValidationRule]] = all_rules
7
+ _rules: Dict[str, Type[Rule]] = all_rules
8
8
 
9
9
  @classmethod
10
- def create_rule(cls, rule_name: str) -> ValidationRule:
10
+ def create_rule(cls, rule_name: str) -> Rule:
11
11
  try:
12
12
  return cls._rules[rule_name]()
13
13
  except KeyError:
14
14
  raise ValueError(f"Unknown validation rule: {rule_name}")
15
15
 
16
16
  @classmethod
17
- def register_rule(cls, name: str, rule_class: Type[ValidationRule]):
17
+ def register_rule(cls, name: str, rule_class: Type[Rule]):
18
18
  cls._rules[name] = rule_class
19
19
 
20
20
  @classmethod
@@ -1,16 +1,16 @@
1
1
  import inspect
2
- from .base import ValidationRule
3
- from . import array, basic, comparison, date, type, files, format, conditional, string, utilities
2
+ from .base import Rule
3
+ from . import array, basic, comparison, date, files, format, boolean, string, numeric, utilities
4
4
 
5
5
  def _collect_rules():
6
- modules = [array, basic, comparison, date, type, files, format, conditional, string, utilities]
6
+ modules = [array, basic, comparison, date, files, format, boolean, string, numeric, utilities]
7
7
  rules = {}
8
8
 
9
9
  for module in modules:
10
10
  for name, obj in inspect.getmembers(module):
11
11
  if (inspect.isclass(obj) and
12
- issubclass(obj, ValidationRule) and
13
- obj != ValidationRule):
12
+ issubclass(obj, Rule) and
13
+ obj != Rule):
14
14
  rules[obj.rule_name] = obj
15
15
  return rules
16
16
 
@@ -21,6 +21,4 @@ for name, cls in all_rules.items():
21
21
  globals()[name] = cls # Export rule name
22
22
 
23
23
 
24
- __all__ = ['ValidationRule'] + \
25
- list(all_rules.keys()) + \
26
- [cls.__name__.replace('Rule', '') for cls in all_rules.values()]
24
+ __all__ = ['Rule'] + [cls.__name__.replace('Rule', '') for cls in all_rules.values()]
validator/rules/array.py CHANGED
@@ -1,9 +1,8 @@
1
- from .base import ValidationRule
1
+ from .base import Rule
2
2
  from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
3
3
 
4
- class ArrayRule(ValidationRule):
4
+ class ArrayRule(Rule):
5
5
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
6
-
7
6
  self._missing_keys = params
8
7
 
9
8
  if params:
@@ -21,42 +20,36 @@ class ArrayRule(ValidationRule):
21
20
  if params:
22
21
  return f"The :attribute must contain the keys: {', '.join(self._missing_keys)}."
23
22
  return f"The :attribute must be an array."
24
-
25
- class ContainsRule(ValidationRule):
23
+
24
+ class DistinctRule(Rule):
26
25
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
27
- if not params:
26
+ if not isinstance(value, (list, tuple, set)):
28
27
  return False
29
28
 
30
- search_value = params[0]
29
+ ignore_case = 'ignore_case' in params
31
30
 
32
- # String contains substring
33
- if isinstance(value, str):
34
- return search_value in value
35
-
36
- # Array contains element
37
- if isinstance(value, (list, tuple, set)):
38
- return search_value in value
31
+ seen = set()
32
+ for item in value:
33
+ compare_val = item
39
34
 
40
- # Dictionary contains key
41
- if isinstance(value, dict):
42
- return search_value in value.keys()
35
+ if ignore_case and isinstance(item, str):
36
+ compare_val = item.lower()
43
37
 
44
- return False
45
-
46
- def message(self, field: str, params: List[str]) -> str:
47
- return f"The :attribute must contain {params[0]}"
48
-
49
- class DistinctRule(ValidationRule):
50
- def validate(self, field: str, value: Any, params: List[str]) -> bool:
51
- if not isinstance(value, (list, tuple, set)):
52
- return False
38
+ if compare_val in seen:
39
+ return False
40
+ seen.add(compare_val)
53
41
 
54
- return len(value) == len(set(value))
42
+ return True
55
43
 
56
44
  def message(self, field: str, params: List[str]) -> str:
57
- return f"The :attribute must contain unique values"
45
+ base_msg = f"The :attribute must contain unique values"
46
+
47
+ if 'ignore_case' in params:
48
+ return f"{base_msg} (case insensitive)"
49
+ else:
50
+ return f"{base_msg} (strict comparison)"
58
51
 
59
- class InArrayRule(ValidationRule):
52
+ class InArrayRule(Rule):
60
53
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
61
54
  if not params:
62
55
  return False
@@ -66,7 +59,7 @@ class InArrayRule(ValidationRule):
66
59
  def message(self, field: str, params: List[str]) -> str:
67
60
  return f"The :attribute must be one of: {', '.join(params)}"
68
61
 
69
- class InArrayKeysRule(ValidationRule):
62
+ class InArrayKeysRule(Rule):
70
63
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
71
64
  if not params or not isinstance(value, dict):
72
65
  return False
validator/rules/base.py CHANGED
@@ -1,24 +1,47 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
3
3
  from enum import Enum
4
- # from .string import pascal_to_snake
5
4
  import inspect
6
5
  import re
7
6
 
8
- class ValidationRule(ABC):
7
+ class Rule(ABC):
9
8
  """Abstract base class for all validation rules"""
10
9
 
10
+ _rule_classes: Dict[str, Type['Rule']] = {}
11
+ _rule_cache: Dict[str, 'Rule'] = {}
12
+
11
13
  def __init__(self, *params: str):
12
14
  self._validator: Optional['Validator'] = None
13
15
  self._params: List[str] = list(params)
14
16
 
15
- def __init_subclass__(cls):
16
- cls.rule_name = cls.pascal_to_snake(cls.__name__)
17
+ def __init_subclass__(cls, name=None):
18
+ cls.rule_name = cls.pascal_to_snake(cls.__name__) if not hasattr(cls, '_name') else cls._name
19
+ cls._register_rule_class()
20
+ cls._generate_rule_methods()
17
21
 
22
+ @classmethod
23
+ def _register_rule_class(cls):
24
+ cls._rule_classes[cls.rule_name] = cls
25
+
18
26
  @property
19
- def params(self) -> List[str]:
20
- return self._params
27
+ def params(self):
28
+ params = []
29
+ for rule_set in self._params:
30
+ if isinstance(rule_set, (list, tuple)):
31
+ params.append(tuple(rule_set))
32
+ else:
33
+ params.append(rule_set)
34
+ return tuple(params)
21
35
 
36
+ @classmethod
37
+ def _generate_rule_methods(cls):
38
+ for rule_name, rule_class in cls._rule_classes.items():
39
+ @classmethod
40
+ def method(cls, *params, rule_class=rule_class):
41
+ return rule_class(*params)
42
+
43
+ setattr(cls.__class__, rule_name, method)
44
+
22
45
  @params.setter
23
46
  def params(self, value: List[str]) -> None:
24
47
  self._params = value
@@ -64,9 +87,10 @@ class ValidationRule(ABC):
64
87
  """Return the name of the rule for error messages."""
65
88
  pass
66
89
 
67
- def _parse_option_values(self, field: str, params: List[str]) -> List[Any]:
90
+ def _parse_option_values(self, field: str, params: List[str], raise_for_error=True) -> List[Any]:
68
91
  """Parse parameters into allowed values, supporting both Enum class and literal values"""
69
- if not params:
92
+
93
+ if not params and raise_for_error:
70
94
  raise ValueError(
71
95
  f"{self.rule_name} rule requires parameters. "
72
96
  f"Use '({self.rule_name}, EnumClass)' or '{self.rule_name}:val1,val2'"
validator/rules/basic.py CHANGED
@@ -1,20 +1,63 @@
1
- from .base import ValidationRule
1
+ from .base import Rule
2
2
  from typing import Any, Dict, List, Optional, Set, Union, Tuple, Type
3
3
 
4
4
  # =============================================
5
5
  # BASIC VALIDATION RULES
6
6
  # =============================================
7
7
 
8
- class AnyOfRule(ValidationRule):
8
+ class AnyOfRule(Rule):
9
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
-
10
+ self._last_failed_rules = [] # Reset failed rules
11
+
12
+ for i, rule_set in enumerate(params):
13
+ if isinstance(rule_set, str):
14
+ rule_set = [rule_set]
15
+
16
+ from validator import Validator
17
+
18
+ temp_validator = Validator(
19
+ {field: value},
20
+ {field: rule_set},
21
+ db_config=getattr(self._validator, 'db_config', None)
22
+ )
23
+
24
+ if temp_validator.validate():
25
+ return True
26
+ else:
27
+ self._last_failed_rules.append({
28
+ 'rules': rule_set,
29
+ 'errors': temp_validator.errors.get(field, [])
30
+ })
31
+
32
+ return False
33
+
14
34
  def message(self, field: str, params: List[str]) -> str:
15
- return f"The :attribute must be one of: {', '.join(params)}"
35
+ if not self._last_failed_rules:
36
+ return f"The :attribute field is invalid."
37
+
38
+ error_messages = []
39
+
40
+ for i, failed in enumerate(self._last_failed_rules, 1):
41
+ rules_str = "|".join(
42
+ r if isinstance(r, str) else getattr(r, 'rule_name', str(r))
43
+ for r in failed['rules']
44
+ )
45
+
46
+ sub_errors = []
47
+ for j, err_msg in enumerate(failed['errors'], 1):
48
+ sub_errors.append(f" {j}. {err_msg}")
49
+
50
+ error_messages.append(
51
+ f"Option {i} (Rules: {rules_str}):\n" +
52
+ "\n".join(sub_errors)
53
+ )
54
+
55
+ return (
56
+ f"The :attribute must satisfy at least one of these conditions:\n" +
57
+ "\n".join(error_messages)
58
+ )
16
59
 
17
- class BailRule(ValidationRule):
60
+ class BailRule(Rule):
18
61
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
19
62
  self.validator._stop_on_first_failure = True
20
63
  return True
@@ -22,49 +65,49 @@ class BailRule(ValidationRule):
22
65
  def message(self, field: str, params: List[str]) -> str:
23
66
  return ""
24
67
 
25
- class RequiredRule(ValidationRule):
68
+ class RequiredRule(Rule):
26
69
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
27
70
  return not self.is_empty(value)
28
71
 
29
72
  def message(self, field: str, params: List[str]) -> str:
30
73
  return f"The :attribute field is required."
31
74
 
32
- class ProhibitedRule(ValidationRule):
75
+ class ProhibitedRule(Rule):
33
76
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
34
77
  return self.is_empty(value)
35
78
 
36
79
  def message(self, field: str, params: List[str]) -> str:
37
80
  return "The :attribute field is must be empty."
38
81
 
39
- class NullableRule(ValidationRule):
82
+ class NullableRule(Rule):
40
83
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
41
84
  return True
42
85
 
43
86
  def message(self, field: str, params: List[str]) -> str:
44
87
  return f"The :attribute may be null."
45
88
 
46
- class FilledRule(ValidationRule):
89
+ class FilledRule(Rule):
47
90
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
48
91
  return value not in ('', None)
49
92
 
50
93
  def message(self, field: str, params: List[str]) -> str:
51
94
  return f"The :attribute field must have a value."
52
95
 
53
- class PresentRule(ValidationRule):
96
+ class PresentRule(Rule):
54
97
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
55
98
  return field in self.validator.data
56
99
 
57
100
  def message(self, field: str, params: List[str]) -> str:
58
101
  return f"The :attribute field must be present."
59
102
 
60
- class MissingRule(ValidationRule):
103
+ class MissingRule(Rule):
61
104
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
62
105
  return value is None
63
106
 
64
107
  def message(self, field: str, params: List[str]) -> str:
65
108
  return f"The :attribute field must be missing."
66
109
 
67
- class ProhibitsRule(ValidationRule):
110
+ class ProhibitsRule(Rule):
68
111
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
69
112
  if not params or value is None:
70
113
  return True
@@ -72,166 +115,22 @@ class ProhibitsRule(ValidationRule):
72
115
 
73
116
  def message(self, field: str, params: List[str]) -> str:
74
117
  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
118
 
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."
105
-
106
- class SometimesRule(ValidationRule):
119
+ class SometimesRule(Rule):
107
120
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
121
+ if value is None:
122
+ self.validator._is_exclude = True
123
+
108
124
  return True
109
125
 
110
126
  def message(self, field: str, params: List[str]) -> str:
111
127
  return ""
112
128
 
113
- class ExcludeRule(ValidationRule):
129
+ class ExcludeRule(Rule):
114
130
  def validate(self, field: str, value: Any, params: List[str]) -> bool:
115
131
  self.validator._is_exclude = True
116
132
 
117
133
  return True
118
134
 
119
135
  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))}"
136
+ return ""