From 5558d96cb999fdfdd782317736ae5b609f381d35 Mon Sep 17 00:00:00 2001 From: zephyrdark Date: Tue, 3 Feb 2026 07:06:55 +0900 Subject: [PATCH] feat: add portfolio CRUD API endpoints --- backend/app/api/__init__.py | 3 +- backend/app/api/portfolio.py | 110 +++++++++++++++++++++++++++++++++++ backend/app/main.py | 3 +- 3 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 backend/app/api/portfolio.py diff --git a/backend/app/api/__init__.py b/backend/app/api/__init__.py index 10e58b6..6add0a3 100644 --- a/backend/app/api/__init__.py +++ b/backend/app/api/__init__.py @@ -1,4 +1,5 @@ from app.api.auth import router as auth_router from app.api.admin import router as admin_router +from app.api.portfolio import router as portfolio_router -__all__ = ["auth_router", "admin_router"] +__all__ = ["auth_router", "admin_router", "portfolio_router"] diff --git a/backend/app/api/portfolio.py b/backend/app/api/portfolio.py new file mode 100644 index 0000000..19770f6 --- /dev/null +++ b/backend/app/api/portfolio.py @@ -0,0 +1,110 @@ +""" +Portfolio management API endpoints. +""" +from typing import List + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from app.core.database import get_db +from app.api.deps import CurrentUser +from app.models.portfolio import Portfolio, PortfolioType +from app.schemas.portfolio import ( + PortfolioCreate, PortfolioUpdate, PortfolioResponse, PortfolioDetail, +) + +router = APIRouter(prefix="/api/portfolios", tags=["portfolios"]) + + +@router.get("", response_model=List[PortfolioResponse]) +async def list_portfolios( + current_user: CurrentUser, + db: Session = Depends(get_db), +): + """Get all portfolios for current user.""" + portfolios = ( + db.query(Portfolio) + .filter(Portfolio.user_id == current_user.id) + .order_by(Portfolio.created_at.desc()) + .all() + ) + return portfolios + + +@router.post("", response_model=PortfolioResponse, status_code=status.HTTP_201_CREATED) +async def create_portfolio( + data: PortfolioCreate, + current_user: CurrentUser, + db: Session = Depends(get_db), +): + """Create a new portfolio.""" + portfolio_type = PortfolioType(data.portfolio_type) + portfolio = Portfolio( + user_id=current_user.id, + name=data.name, + portfolio_type=portfolio_type, + ) + db.add(portfolio) + db.commit() + db.refresh(portfolio) + return portfolio + + +@router.get("/{portfolio_id}", response_model=PortfolioResponse) +async def get_portfolio( + portfolio_id: int, + current_user: CurrentUser, + db: Session = Depends(get_db), +): + """Get a portfolio by ID.""" + portfolio = db.query(Portfolio).filter( + Portfolio.id == portfolio_id, + Portfolio.user_id == current_user.id, + ).first() + if not portfolio: + raise HTTPException(status_code=404, detail="Portfolio not found") + return portfolio + + +@router.put("/{portfolio_id}", response_model=PortfolioResponse) +async def update_portfolio( + portfolio_id: int, + data: PortfolioUpdate, + current_user: CurrentUser, + db: Session = Depends(get_db), +): + """Update a portfolio.""" + portfolio = db.query(Portfolio).filter( + Portfolio.id == portfolio_id, + Portfolio.user_id == current_user.id, + ).first() + if not portfolio: + raise HTTPException(status_code=404, detail="Portfolio not found") + + if data.name is not None: + portfolio.name = data.name + if data.portfolio_type is not None: + portfolio.portfolio_type = PortfolioType(data.portfolio_type) + + db.commit() + db.refresh(portfolio) + return portfolio + + +@router.delete("/{portfolio_id}", status_code=status.HTTP_204_NO_CONTENT) +async def delete_portfolio( + portfolio_id: int, + current_user: CurrentUser, + db: Session = Depends(get_db), +): + """Delete a portfolio.""" + portfolio = db.query(Portfolio).filter( + Portfolio.id == portfolio_id, + Portfolio.user_id == current_user.id, + ).first() + if not portfolio: + raise HTTPException(status_code=404, detail="Portfolio not found") + + db.delete(portfolio) + db.commit() + return None diff --git a/backend/app/main.py b/backend/app/main.py index 143977e..b9476b7 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -4,7 +4,7 @@ Galaxy-PO Backend API from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from app.api import auth_router, admin_router +from app.api import auth_router, admin_router, portfolio_router app = FastAPI( title="Galaxy-PO API", @@ -23,6 +23,7 @@ app.add_middleware( # Include routers app.include_router(auth_router) app.include_router(admin_router) +app.include_router(portfolio_router) @app.get("/health")