afc55ab910
- 新建 device 设备表(设备/系统信息 + 网络/时区/模拟器/位置 + 关联用户 + 状态/时间戳), 以客户端 device_id 唯一标识;登录后回填 user_id,游客态可空 - 原 device 模型改名 device_liveness(实为无障碍存活表),腾出 device 名给新表并保持 表名与实体名一致;同步更新 __init__ / repositories / admin queries / 文档引用 - 新增 POST /api/v1/device/report:软鉴权(带 JWT 绑用户、游客也收),按 device_id upsert; 设备信息非空才覆盖,位置 latitude/longitude 整字段覆盖含清空(以本次上报实际为准) - 新增 alembic migration bb47051068c8 建 device 表(裁掉 autogenerate 带出的无关表漂移) - 补 /device/report 端点与 upsert 单元测试 4 例
52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
"""设备档案上报 endpoint(device 表)。
|
|
|
|
POST /api/v1/device/report — 客户端上报设备当前信息,按 device_id upsert 到 device 表。
|
|
软鉴权:带合法 Bearer → 设备关联到该用户;游客态(无 token)也接受,user_id 暂空。
|
|
|
|
注意与 /api/v1/device/register(app/api/v1/device.py)区分:那个是无障碍存活注册,写
|
|
device_liveness 表、硬鉴权;本端点是设备信息档案,写 device 表、软鉴权。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Request
|
|
|
|
from app.api.deps import DbSession, OptionalUser
|
|
from app.repositories import device_profile as device_profile_repo
|
|
from app.schemas.device_profile import DeviceReportOut, DeviceReportRequest
|
|
|
|
logger = logging.getLogger("shagua.device_profile")
|
|
|
|
router = APIRouter(prefix="/api/v1/device", tags=["device"])
|
|
|
|
|
|
def _client_ip(request: Request) -> str | None:
|
|
"""客户端 IP:生产经 nginx 反代优先 X-Forwarded-For 第一段,否则直连 IP。"""
|
|
xff = request.headers.get("x-forwarded-for")
|
|
if xff:
|
|
return xff.split(",")[0].strip()
|
|
return request.client.host if request.client else None
|
|
|
|
|
|
@router.post("/report", response_model=DeviceReportOut, summary="上报设备信息(设备档案 upsert)")
|
|
def report_device(
|
|
req: DeviceReportRequest,
|
|
request: Request,
|
|
user: OptionalUser,
|
|
db: DbSession,
|
|
) -> DeviceReportOut:
|
|
device = device_profile_repo.upsert_device(
|
|
db,
|
|
req,
|
|
user_id=user.id if user else None,
|
|
last_ip=_client_ip(request),
|
|
)
|
|
logger.info(
|
|
"device report device_id=%s user_id=%s has_loc=%s",
|
|
req.device_id,
|
|
device.user_id,
|
|
req.latitude is not None,
|
|
)
|
|
return DeviceReportOut()
|