""" 数据订阅 API 路由 """ from typing import Annotated, List, Optional from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from app.schemas import ( SubscriptionCreate, SubscriptionResponse, ResponseData ) from app.services.subscription_service import SubscriptionService from app.api.v1.auth import get_current_user from app.models import User from app.db.init_db import get_sqlite_db router = APIRouter() @router.post("", response_model=ResponseData) async def create_subscription( request: SubscriptionCreate, current_user: Annotated[User, Depends(get_current_user)], db: Session = Depends(get_sqlite_db) ): """ 创建数据订阅 - **symbol**: 品种代码 - **period**: 周期 (可选,仅 kline 类型需要) - **subscription_type**: 订阅类型 (kline, realtime) """ # 检查是否已存在相同订阅 from app.models import Subscription existing = db.query(Subscription).filter( Subscription.user_id == current_user.id, Subscription.symbol == request.symbol, Subscription.period == request.period, Subscription.subscription_type == request.subscription_type, Subscription.is_active == True ).first() if existing: raise HTTPException( status_code=400, detail=f"订阅已存在:{request.symbol} ({request.subscription_type})" ) subscription = SubscriptionService.create_subscription( user_id=current_user.id, symbol=request.symbol, period=request.period, subscription_type=request.subscription_type ) return ResponseData( code=0, message="success", data={ "id": subscription.id, "symbol": subscription.symbol, "period": subscription.period, "subscription_type": subscription.subscription_type, "is_active": subscription.is_active, "created_at": subscription.created_at.isoformat() } ) @router.get("", response_model=ResponseData) async def list_subscriptions( subscription_type: Annotated[Optional[str], Query(description="订阅类型")] = None, current_user: Annotated[User, Depends(get_current_user)] = None ): """获取用户订阅列表""" subscriptions = SubscriptionService.get_user_subscriptions( current_user.id, subscription_type ) return ResponseData( code=0, message="success", data=[ { "id": s.id, "symbol": s.symbol, "period": s.period, "subscription_type": s.subscription_type, "is_active": s.is_active, "created_at": s.created_at.isoformat() } for s in subscriptions ] ) @router.get("/{subscription_id}", response_model=ResponseData) async def get_subscription( subscription_id: int, current_user: Annotated[User, Depends(get_current_user)] ): """获取订阅详情""" subscription = SubscriptionService.get_subscription_by_id( subscription_id, current_user.id ) if not subscription: raise HTTPException( status_code=404, detail="Subscription not found" ) return ResponseData( code=0, message="success", data={ "id": subscription.id, "symbol": subscription.symbol, "period": subscription.period, "subscription_type": subscription.subscription_type, "is_active": subscription.is_active, "created_at": subscription.created_at.isoformat() } ) @router.delete("/{subscription_id}", response_model=ResponseData) async def cancel_subscription( subscription_id: int, current_user: Annotated[User, Depends(get_current_user)] ): """取消订阅""" success = SubscriptionService.cancel_subscription( subscription_id, current_user.id ) if not success: raise HTTPException( status_code=404, detail="Subscription not found" ) return ResponseData( code=0, message="success", data={"id": subscription_id, "status": "cancelled"} ) @router.get("/symbol/{symbol}/subscribers", response_model=ResponseData) async def get_subscribers( symbol: str, subscription_type: Annotated[str, Query(description="订阅类型")] = "kline", current_user: Annotated[User, Depends(get_current_user)] = None ): """获取订阅某品种的用户数量 (管理接口)""" # 这里只返回数量,不返回具体用户 ID 以保护隐私 user_ids = SubscriptionService.get_subscribers_for_symbol(symbol, subscription_type) return ResponseData( code=0, message="success", data={ "symbol": symbol, "subscription_type": subscription_type, "subscriber_count": len(user_ids) } )