""" FCM 推送 API — Android 设备 Token 管理 提供设备推送令牌的注册和注销接口。 """ from __future__ import annotations import logging from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from app.api.auth import get_current_user from app.core.database import SessionLocal from app.models.fcm_token import FcmToken from app.models.user import User logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/v1/fcm", tags=["fcm"]) class FcmRegisterRequest(BaseModel): token: str = Field(..., min_length=32, max_length=512, description="FCM/APNs 设备令牌") platform: str = Field(default="android", description="android / ios / web") @router.post("/register") async def register_fcm_token( req: FcmRegisterRequest, current_user: User = Depends(get_current_user), ): """注册设备推送 Token。同一 Token 多次注册会更新绑定用户和时间。""" db = SessionLocal() try: existing = db.query(FcmToken).filter(FcmToken.token == req.token).first() if existing: existing.user_id = current_user.id existing.platform = req.platform db.commit() logger.info("FCM Token 已更新: user=%s platform=%s", current_user.id, req.platform) return {"status": "updated", "id": str(existing.id)} fcm = FcmToken( user_id=current_user.id, token=req.token, platform=req.platform, ) db.add(fcm) db.commit() db.refresh(fcm) logger.info("FCM Token 已注册: user=%s platform=%s", current_user.id, req.platform) return {"status": "registered", "id": str(fcm.id)} finally: db.close() @router.delete("/unregister") async def unregister_fcm_token( token: str, current_user: User = Depends(get_current_user), ): """注销设备推送 Token。""" db = SessionLocal() try: fcm = ( db.query(FcmToken) .filter(FcmToken.token == token, FcmToken.user_id == current_user.id) .first() ) if fcm: db.delete(fcm) db.commit() logger.info("FCM Token 已注销: user=%s", current_user.id) return {"status": "deleted"} return {"status": "not_found"} finally: db.close()