Files
webhook/db.py
zhilv 9ffe78a9c2 feat(command): 添加动态配置、黑白名单与后台管理界面
- 新增 SQLite 数据库层(db.py)持久化命令监听配置,支持热更新无需重启
- 命令过滤从白名单扩展为黑白名单双模式(COMMAND_LIST_MODE: allow/deny)
- 新增后台管理页面 /admin/,侧边栏布局,支持在线修改所有命令监听配置
- 新增 REST API:GET/PUT /api/settings、POST /api/settings/reload
- 新增 rebuild_pattern() 支持配置变更后正则动态重编译
- 中间件放行 /admin 和 /api 路径免鉴权
- 添加 aiosqlite 依赖
2026-05-03 15:22:53 +08:00

83 lines
2.7 KiB
Python

"""SQLite 数据库层:存储可动态修改的配置项。"""
import aiosqlite
from pathlib import Path
DB_PATH = Path(__file__).parent / "data" / "webhook.db"
# 需要持久化的配置项及其默认值(从 .env 加载时的回退)
SETTINGS_DEFAULTS: dict[str, str] = {
"command_prefix": "#",
"command_length_min": "2",
"command_length_max": "4",
"command_scope": "all",
"command_list_mode": "allow",
"command_allowed_groups": "",
"command_denied_groups": "",
"command_allowed_users": "",
"command_denied_users": "",
"command_at_sender": "true",
"command_callback_url": "",
"command_callback_timeout": "180",
}
async def init_db() -> None:
"""建表 + 首次启动时写入默认值。"""
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
async with aiosqlite.connect(DB_PATH) as db:
await db.execute(
"""
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL DEFAULT ''
)
"""
)
await db.commit()
# 首次启动:插入不存在的默认值
for key, default in SETTINGS_DEFAULTS.items():
await db.execute(
"INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)",
(key, default),
)
await db.commit()
async def get_setting(key: str) -> str | None:
"""读取单个配置值,不存在返回 None。"""
async with aiosqlite.connect(DB_PATH) as db:
cursor = await db.execute("SELECT value FROM settings WHERE key = ?", (key,))
row = await cursor.fetchone()
return row[0] if row else None
async def get_settings() -> dict[str, str]:
"""读取全部配置,返回 {key: value} 字典。"""
async with aiosqlite.connect(DB_PATH) as db:
cursor = await db.execute("SELECT key, value FROM settings")
rows = await cursor.fetchall()
return {row[0]: row[1] for row in rows}
async def update_setting(key: str, value: str) -> None:
"""更新单个配置值。"""
async with aiosqlite.connect(DB_PATH) as db:
await db.execute(
"INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = ?",
(key, value, value),
)
await db.commit()
async def update_settings(data: dict[str, str]) -> None:
"""批量更新配置值。"""
async with aiosqlite.connect(DB_PATH) as db:
for key, value in data.items():
await db.execute(
"INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = ?",
(key, value, value),
)
await db.commit()