You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
5.0 KiB

"""
数据订阅 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)
}
)