agentbond-api / app /api /routes.py
Karan6124's picture
feat(api): filter cases by authenticated user and protect endpoints
1ba28b2
Raw
History Blame Contribute Delete
4.87 kB
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List, Optional
from pydantic import BaseModel, Field
from app.services.database import get_db
from app.services.context_manager import ContextManager
from app.models.schemas import CaseContext, CaseStatus
from app.workers.celery_worker import run_case_manager_task
from app.api.auth import get_current_user
from app.models.database_models import UserModel
router = APIRouter(prefix="/api/cases", tags=["Cases"])
class CreateCaseRequest(BaseModel):
problem_statement: str = Field(..., example="Why are my Instagram views dropping?")
constraints: Optional[List[str]] = Field(default_factory=list, example=["creator niche = tech"])
@router.post("", response_model=CaseContext, status_code=status.HTTP_201_CREATED)
def create_case(
payload: CreateCaseRequest,
db: Session = Depends(get_db),
current_user: UserModel = Depends(get_current_user)
):
"""
Initializes a new investigation case in the shared context database and links it to the current user.
"""
try:
context = ContextManager.create_context(
db=db,
problem_statement=payload.problem_statement,
constraints=payload.constraints,
user_id=current_user.id
)
return context
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to create case: {str(e)}"
)
@router.get("/{case_id}", response_model=CaseContext)
def get_case(
case_id: str,
db: Session = Depends(get_db),
current_user: UserModel = Depends(get_current_user)
):
"""
Retrieves the complete shared context for a case, validating user authorization.
"""
context = ContextManager.get_context(db=db, case_id=case_id)
if not context:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Case with ID {case_id} not found."
)
from app.models.database_models import CaseContextModel
case_db = db.query(CaseContextModel).filter(CaseContextModel.case_id == case_id).first()
if case_db and case_db.user_id and case_db.user_id != current_user.id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied to this case."
)
return context
@router.post("/{case_id}/decompose", response_model=CaseContext, status_code=status.HTTP_202_ACCEPTED)
def decompose_case(
case_id: str,
db: Session = Depends(get_db),
current_user: UserModel = Depends(get_current_user)
):
"""
Triggers the Case Manager Agent task asynchronously via Celery, validating user authorization.
"""
from app.models.database_models import CaseContextModel
case_db = db.query(CaseContextModel).filter(CaseContextModel.case_id == case_id).first()
if not case_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Case with ID {case_id} not found."
)
if case_db.user_id and case_db.user_id != current_user.id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied to this case."
)
context = ContextManager.get_context(db=db, case_id=case_id)
if context.hypotheses:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="This case has already been decomposed into hypotheses."
)
# 2. Update status to investigating
updated_context = ContextManager.update_status(db=db, case_id=case_id, status=CaseStatus.INVESTIGATING)
try:
# 3. Dispatch Celery task to the Redis broker
run_case_manager_task.delay(case_id)
# Return the updated context showing the new 'investigating' status immediately
return updated_context
except Exception as e:
# Rollback status to failed if task dispatch fails
ContextManager.update_status(db=db, case_id=case_id, status=CaseStatus.FAILED)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to queue agent task: {str(e)}"
)
@router.get("", response_model=List[CaseContext])
def get_cases(
limit: int = 20,
db: Session = Depends(get_db),
current_user: UserModel = Depends(get_current_user)
):
"""
Retrieves all investigation cases in the database belonging to the current user.
"""
try:
return ContextManager.get_all_contexts(db=db, limit=limit, user_id=current_user.id)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to fetch cases: {str(e)}"
)