Files
SignatureSystem/lib/validators.py

160 lines
4.8 KiB
Python
Raw Normal View History

2026-07-20 13:16:17 +08:00
import re
import logging
logger = logging.getLogger(__name__)
USER_ID_PATTERN = re.compile(r'^[a-zA-Z0-9]+$')
def validate_user_id(user_id):
if not user_id:
return False, "人员ID不能为空"
if not USER_ID_PATTERN.match(user_id):
return False, "人员ID仅支持大小写英文字母和数字"
if len(user_id) > 50:
return False, "人员ID长度不能超过50"
return True, ""
def validate_user_name(user_name):
if not user_name:
return False, "人员姓名不能为空"
if len(user_name) > 100:
return False, "人员姓名长度不能超过100"
return True, ""
def validate_height(height):
if height is None or height == "":
return True, None
try:
h = float(height)
if 0.1 <= h <= 10.0:
return True, round(h, 1)
return False, f"高度 {height} 超出有效范围 0.1~10.0"
except (ValueError, TypeError):
return False, f"高度 {height} 不是有效数值"
def validate_noise_level(level):
if level is None or level == "":
return True, 0
try:
n = int(level)
if 0 <= n <= 10:
return True, n
return False, f"噪声强度 {level} 超出有效范围 0~10"
except (ValueError, TypeError):
return False, f"噪声强度 {level} 不是有效整数"
def validate_rotate(min_val, max_val):
def _clamp(v):
try:
v = int(v)
return max(-180, min(180, v))
except (ValueError, TypeError):
return 0
r_min = _clamp(min_val) if min_val not in (None, "") else 0
r_max = _clamp(max_val) if max_val not in (None, "") else 0
return True, (r_min, r_max)
def validate_match_mode(mode):
if mode in ('upload', 'id', 'name', 'auto'):
return True, ""
return False, f"匹配模式 '{mode}' 无效,支持: upload/id/name/auto"
def validate_docx_name(name):
if not name:
return False, "文件名不能为空"
if not name.lower().endswith('.docx'):
return False, "仅支持.docx格式"
return True, ""
def validate_docx_size(data_bytes, max_bytes):
if not isinstance(data_bytes, (bytes, bytearray)):
return False, "文档数据无效"
if len(data_bytes) > max_bytes:
return False, f"文档大小 {len(data_bytes)} 字节超过限制 {max_bytes} 字节"
return True, ""
def validate_image_size(data_bytes, max_bytes):
if not isinstance(data_bytes, (bytes, bytearray)):
return False, "图片数据无效"
if len(data_bytes) > max_bytes:
return False, f"图片大小 {len(data_bytes)} 字节超过限制 {max_bytes} 字节"
return True, ""
def validate_capture_group(group):
if group is None or group == "":
return False, "捕获组序号不能为空"
try:
g = int(group)
except (ValueError, TypeError):
return False, f"捕获组序号 '{group}' 不是整数"
if g < 1:
return False, "捕获组序号禁止为 0 或负数,必须 >=1"
return True, g
def validate_rule(rule):
errors = []
if not rule.get('name'):
errors.append("规则名称不能为空")
pattern = rule.get('pattern')
if not pattern:
errors.append("规则正则表达式不能为空")
else:
try:
re.compile(pattern)
except re.error as e:
errors.append(f"正则表达式非法: {e}")
valid, msg_or_val = validate_capture_group(rule.get('capture_group'))
if not valid:
errors.append(msg_or_val)
cell_mode = rule.get('cell_mode', 'single')
if cell_mode not in ('single', 'horizontal', 'vertical'):
errors.append(f"表格方式 '{cell_mode}' 无效")
cell_match = rule.get('cell_match', 'partial')
if cell_match not in ('partial', 'whole'):
errors.append(f"匹配方式 '{cell_match}' 无效")
return errors
def validate_sign_request(params):
errors = []
valid, msg = validate_docx_name(params.get('docx_name', ''))
if not valid:
errors.append(msg)
valid, msg = validate_match_mode(params.get('match_mode', ''))
if not valid:
errors.append(msg)
stamps = params.get('stamps', [])
if params.get('match_mode') != 'auto' and not stamps:
errors.append("非auto模式必须提供盖章项列表")
if len(stamps) > 100:
errors.append("盖章项不能超过100个")
height = params.get('height')
if height is not None and height != "":
valid, _ = validate_height(height)
if not valid:
errors.append(f"全局高度无效: {validate_height(height)[1]}")
noise = params.get('noise_level')
if noise is not None and noise != "":
valid, _ = validate_noise_level(noise)
if not valid:
errors.append(f"全局噪声无效: {validate_noise_level(noise)[1]}")
return errors