- 旧平铺模块(data/data_utils/database_op/image_builder*/get_bf6_data/ gametools_bf6/bf6_data/img_utils)拆分为 handlers(绑定/查询)、 services(fetchers/processing/query)、utils(渲染/参数)分层; 新增 repository.py / config.py / paths.py - 字体/图片/模板资源迁入 res/,新增 BF2042 卡面素材(bg/object_icon 等) - browser_ext/:BF2042 扩展捕获桥(WS 直连兜底通道)源码入库 - 新增 hexi/web/src/plugins/bf_bot 前端管理页 - 新增 tests:test_bf_bot_helpers / repository / tracker_api Co-Authored-By: Claude Code <noreply@anthropic.com>
77 lines
2.8 KiB
Python
77 lines
2.8 KiB
Python
"""BF查询 —— Web API 子应用(挂载到 /api/bf_bot):QQ↔EAID 绑定管理。
|
||
|
||
读写全部走 repository.py(与群里 /绑定 /解绑 命令改的是同一个库文件)。
|
||
鉴权走 hexi.web_hub.web_auth(OAuth2 + SQLite),与统一管理台 /hub 共用登录态。
|
||
**每条路由都要自带 `dependencies=[auth]`** —— mount 层没有兜底,漏一条就是匿名可访问。
|
||
前端页面:hexi/web/src/plugins/bf_bot/index.tsx。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from fastapi import FastAPI
|
||
from fastapi.responses import JSONResponse
|
||
|
||
from hexi.web_hub.web_auth import require_admin
|
||
|
||
from ..repository import UserManager
|
||
|
||
API = require_admin
|
||
|
||
|
||
def _ok(data=None, msg: str = "ok") -> JSONResponse:
|
||
return JSONResponse({"status": 0, "msg": msg, "data": data})
|
||
|
||
|
||
def _fail(msg: str, status: int = 400) -> JSONResponse:
|
||
return JSONResponse({"status": status, "msg": msg})
|
||
|
||
|
||
def build_admin_app() -> FastAPI:
|
||
"""构建绑定管理 API 子应用(挂载到 /api/bf_bot)。"""
|
||
app = FastAPI(title="BF查询绑定管理")
|
||
auth = require_admin
|
||
|
||
@app.get("/bindings", response_class=JSONResponse, dependencies=[auth])
|
||
async def list_bindings(page: int = 1, per_page: int = 10):
|
||
"""绑定列表(QQ / EA 名称 / EA 双 ID / 标签 / 绑定时间),按绑定时间倒序分页。"""
|
||
page = max(1, page)
|
||
per_page = min(max(1, per_page), 100)
|
||
manager = UserManager()
|
||
total = manager.count_users()
|
||
users = manager.list_users(limit=per_page, offset=(page - 1) * per_page)
|
||
return _ok(
|
||
{
|
||
"bindings": [
|
||
{
|
||
"qq_id": u.get("qq_id"),
|
||
"ea_player_name": u.get("ea_player_name"),
|
||
"ea_player_id": u.get("ea_player_id"),
|
||
"ea_user_id": u.get("ea_user_id"),
|
||
"designation": u.get("designation"),
|
||
"create_time": u.get("create_time"),
|
||
}
|
||
for u in users
|
||
],
|
||
"total": total,
|
||
"page": page,
|
||
"per_page": per_page,
|
||
}
|
||
)
|
||
|
||
@app.delete("/bindings/{qq_id}", response_class=JSONResponse, dependencies=[auth])
|
||
async def delete_binding(qq_id: str):
|
||
"""解绑某 QQ(等价于群里的「解绑」)。"""
|
||
manager = UserManager()
|
||
record = manager.get_user_by_qq(qq_id)
|
||
if not record:
|
||
return _fail("未找到该 QQ 的绑定记录", 404)
|
||
rows = manager.delete_user_by_qq(qq_id)
|
||
if rows > 0:
|
||
return _ok(
|
||
{"qq_id": qq_id, "ea_player_name": record.get("ea_player_name")},
|
||
f"已解绑 {record.get('ea_player_name')}",
|
||
)
|
||
return _fail("删除失败")
|
||
|
||
return app
|