60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
"""Watchlist router — manage user's curated watchlist."""
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.dependencies import get_db, require_access
|
|
from app.models.user import User
|
|
from app.schemas.common import APIEnvelope
|
|
from app.schemas.watchlist import WatchlistEntryResponse
|
|
from app.services.watchlist_service import (
|
|
add_manual_entry,
|
|
get_watchlist,
|
|
remove_entry,
|
|
)
|
|
|
|
router = APIRouter(tags=["watchlist"])
|
|
|
|
|
|
@router.get("/watchlist", response_model=APIEnvelope)
|
|
async def list_watchlist(
|
|
sort_by: str = Query(
|
|
"composite",
|
|
description=(
|
|
"Sort by: composite, rr, or a dimension name "
|
|
"(technical, sr_quality, sentiment, fundamental, momentum)"
|
|
),
|
|
),
|
|
user: User = Depends(require_access),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> APIEnvelope:
|
|
"""Get current user's watchlist with enriched data."""
|
|
rows = await get_watchlist(db, user.id, sort_by=sort_by)
|
|
data = [WatchlistEntryResponse(**r).model_dump(mode="json") for r in rows]
|
|
return APIEnvelope(status="success", data=data)
|
|
|
|
|
|
@router.post("/watchlist/{symbol}", response_model=APIEnvelope)
|
|
async def add_to_watchlist(
|
|
symbol: str,
|
|
user: User = Depends(require_access),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> APIEnvelope:
|
|
"""Add a manual entry to the watchlist."""
|
|
entry = await add_manual_entry(db, user.id, symbol)
|
|
return APIEnvelope(
|
|
status="success",
|
|
data={"symbol": symbol.strip().upper(), "entry_type": entry.entry_type},
|
|
)
|
|
|
|
|
|
@router.delete("/watchlist/{symbol}", response_model=APIEnvelope)
|
|
async def remove_from_watchlist(
|
|
symbol: str,
|
|
user: User = Depends(require_access),
|
|
db: AsyncSession = Depends(get_db),
|
|
) -> APIEnvelope:
|
|
"""Remove an entry from the watchlist."""
|
|
await remove_entry(db, user.id, symbol)
|
|
return APIEnvelope(status="success", data=None)
|