validator.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. # -*- coding: utf-8 -*-
  2. import re
  3. from datetime import datetime
  4. from typing import Annotated
  5. from pydantic import AfterValidator, PlainSerializer, WithJsonSchema
  6. from app.common.constant import RET
  7. from app.core.exceptions import CustomException
  8. # 自定义日期时间字符串类型
  9. DateTimeStr = Annotated[
  10. datetime,
  11. AfterValidator(lambda x: datetime_validator(x)),
  12. PlainSerializer(lambda x: x.strftime('%Y-%m-%d %H:%M:%S') if isinstance(x, datetime) else str(x), return_type=str),
  13. WithJsonSchema({'type': 'string'}, mode='serialization')
  14. ]
  15. # 自定义手机号类型
  16. Telephone = Annotated[
  17. str,
  18. AfterValidator(lambda x: mobile_validator(x)),
  19. PlainSerializer(lambda x: x, return_type=str),
  20. WithJsonSchema({'type': 'string'}, mode='serialization')
  21. ]
  22. # 自定义邮箱类型
  23. Email = Annotated[
  24. str,
  25. AfterValidator(lambda x: email_validator(x)),
  26. PlainSerializer(lambda x: x, return_type=str),
  27. WithJsonSchema({'type': 'string'}, mode='serialization')
  28. ]
  29. def datetime_validator(value: str | datetime) -> datetime:
  30. """
  31. 日期格式验证器。
  32. 参数:
  33. - value (str | datetime): 日期值。
  34. 返回:
  35. - datetime: 格式化后的日期。
  36. 异常:
  37. - CustomException: 日期格式无效时抛出。
  38. """
  39. pattern = "%Y-%m-%d %H:%M:%S"
  40. try:
  41. if isinstance(value, str):
  42. return datetime.strptime(value, pattern)
  43. elif isinstance(value, datetime):
  44. return value
  45. except Exception:
  46. raise CustomException(code=RET.ERROR.code, msg="无效的日期格式")
  47. def email_validator(value: str) -> str:
  48. """
  49. 邮箱地址验证器。
  50. 参数:
  51. - value (str): 邮箱地址。
  52. 返回:
  53. - str: 验证后的邮箱地址。
  54. 异常:
  55. - CustomException: 邮箱格式无效时抛出。
  56. """
  57. if not value:
  58. raise CustomException(code=RET.ERROR.code, msg="邮箱地址不能为空")
  59. regex = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
  60. if not re.match(regex, value):
  61. raise CustomException(code=RET.ERROR.code, msg="邮箱地址格式不正确")
  62. return value
  63. def mobile_validator(value: str | None) -> str | None:
  64. """
  65. 手机号验证器。
  66. 参数:
  67. - value (str | None): 手机号。
  68. 返回:
  69. - str | None: 验证后的手机号。
  70. 异常:
  71. - CustomException: 手机号格式无效时抛出。
  72. """
  73. if not value:
  74. return value
  75. if len(value) != 11 or not value.isdigit():
  76. raise CustomException(code=RET.ERROR.code, msg="手机号格式不正确")
  77. regex = r'^1(3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8[0-9]|9[0-9])\d{8}$'
  78. if not re.match(regex, value):
  79. raise CustomException(code=RET.ERROR.code, msg="手机号格式不正确")
  80. return value
  81. def menu_request_validator(data):
  82. """
  83. 菜单请求数据验证器。
  84. 参数:
  85. - data (Any): 请求数据。
  86. 返回:
  87. - Any: 验证后的请求数据。
  88. 异常:
  89. - CustomException: 请求数据无效时抛出。
  90. """
  91. menu_types = {1: "目录", 2: "功能", 3: "权限", 4: "外链"}
  92. if data.type not in menu_types:
  93. raise CustomException(code=RET.ERROR.code, msg=f"菜单类型必须为: {','.join(map(str, menu_types.keys()))}")
  94. if data.type in [1, 2]:
  95. if not data.route_name:
  96. raise CustomException(code=RET.ERROR.code, msg="路由名称不能为空")
  97. if not data.route_path:
  98. raise CustomException(code=RET.ERROR.code, msg="路由路径不能为空")
  99. if data.type == 2 and not data.component_path:
  100. raise CustomException(code=RET.ERROR.code, msg="组件路径不能为空")
  101. return data
  102. def role_permission_request_validator(data):
  103. """
  104. 角色权限设置数据验证器。
  105. 参数:
  106. - data (Any): 请求数据。
  107. 返回:
  108. - Any: 验证后的请求数据。
  109. 异常:
  110. - CustomException: 请求数据无效时抛出。
  111. """
  112. data_scopes = {
  113. 1: "仅本人数据权限",
  114. 2: "本部门数据权限",
  115. 3: "本部门及以下数据权限",
  116. 4: "全部数据权限",
  117. 5: "自定义数据权限"
  118. }
  119. if data.data_scope not in data_scopes:
  120. raise CustomException(code=RET.ERROR.code, msg=f"数据权限范围必须为: {','.join(map(str, data_scopes.keys()))}")
  121. if not data.role_ids:
  122. raise CustomException(code=RET.ERROR.code, msg="角色不能为空")
  123. return data