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
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)
|
|
}
|
|
)
|