初始提交:QQ 群入群验证机器人

基于 qqbotsdk-py 的入群验证:进群发按钮验证码、完成前禁言、
超时踢出(11253 时兜底长期禁言)、乱点他人按钮处罚、状态持久化
与重启恢复。38 个单元/集成测试。
This commit is contained in:
snowy-yang committed 2026-10-04 18:44:08 +08:00
commit 755013b9db
17 files changed
+1864

No files matched your search

+70
View File
@@ -0,0 +1,70 @@
"""验证业务配置:SDK 的 .env(AppID/AppSecret 等)之上再读验证参数。
全部项都有内置默认值,.env 里按需覆盖;取值越界或非法启动即报错。
"""
from __future__ import annotations
import os
from dataclasses import dataclass
from pathlib import Path
from dotenv import load_dotenv
# 幂等:qqbotsdk 导入时也会 load_dotenv(),且不会覆盖已存在的环境变量
load_dotenv()
def _int_env(name: str, default: int, lo: int, hi: int) -> int:
raw = os.getenv(name, "").strip()
if not raw:
return default
try:
value = int(raw)
except ValueError:
raise ValueError(f"{name} 应为整数,实际: {raw!r}") from None
if not lo <= value <= hi:
raise ValueError(f"{name} 应在 {lo}~{hi} 之间,实际: {value}")
return value
def _bool_env(name: str, default: bool) -> bool:
raw = os.getenv(name, "").strip().lower()
if not raw:
return default
if raw in ("1", "true", "yes", "on"):
return True
if raw in ("0", "false", "no", "off"):
return False
raise ValueError(f"{name} 应为 true/false,实际: {raw!r}")
@dataclass(frozen=True, slots=True)
class AuthConfig:
"""验证业务参数,含义与默认值见 .env.example。"""
verify_timeout_minutes: int
pending_mute_hours: int
timeout_kick: bool
timeout_fallback_mute_hours: int
captcha_options: int
verified_trust_days: int
foreign_click_limit: int
foreign_click_mute_minutes: int
data_dir: Path
@classmethod
def load(cls) -> "AuthConfig":
return cls(
verify_timeout_minutes=_int_env("VERIFY_TIMEOUT_MINUTES", 10, 1, 1440),
pending_mute_hours=_int_env("PENDING_MUTE_HOURS", 24, 1, 24 * 30),
timeout_kick=_bool_env("TIMEOUT_KICK", True),
timeout_fallback_mute_hours=_int_env(
"TIMEOUT_FALLBACK_MUTE_HOURS", 72, 1, 24 * 30
),
captcha_options=_int_env("CAPTCHA_OPTIONS", 4, 2, 5),
verified_trust_days=_int_env("VERIFIED_TRUST_DAYS", 0, 0, 365),
foreign_click_limit=_int_env("FOREIGN_CLICK_LIMIT", 3, 1, 100),
foreign_click_mute_minutes=_int_env("FOREIGN_CLICK_MUTE_MINUTES", 5, 1, 1440),
data_dir=Path(os.getenv("DATA_DIR", "data")),
)