wrongmove/api/decision_routes.py

104 lines
3.3 KiB
Python
Raw Normal View History

import logging
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel, Field
from api.auth import User, get_current_user
from database import engine
from repositories.decision_repository import DecisionRepository
from repositories.user_repository import UserRepository
from services import decision_service
logger = logging.getLogger("uvicorn")
decision_router = APIRouter(prefix="/api/decisions", tags=["decisions"])
class SetDecisionRequest(BaseModel):
decision: str = Field(description="'liked' or 'disliked'")
listing_type: str = Field(description="'RENT' or 'BUY'")
class DecisionResponse(BaseModel):
listing_id: int
listing_type: str
decision: str
created_at: str
updated_at: str
def _get_user_id(user: User) -> int:
"""Resolve auth User to database user ID."""
user_repo = UserRepository(engine)
db_user = user_repo.get_user_by_email(user.email)
if db_user is None:
# Auto-create user on first decision interaction
db_user = user_repo.create_user(user.email)
if db_user.id is None:
raise HTTPException(status_code=500, detail="Failed to create user")
return db_user.id
def _to_response(d: decision_service.ListingDecision) -> DecisionResponse:
return DecisionResponse(
listing_id=d.listing_id,
listing_type=d.listing_type,
decision=d.decision,
created_at=d.created_at.isoformat(),
updated_at=d.updated_at.isoformat(),
)
@decision_router.put("/{listing_id}", response_model=DecisionResponse)
async def set_decision(
user: Annotated[User, Depends(get_current_user)],
listing_id: int,
body: SetDecisionRequest,
) -> DecisionResponse:
"""Set or update a like/dislike decision for a listing."""
user_id = _get_user_id(user)
repo = DecisionRepository(engine)
try:
result = decision_service.set_decision(
repo,
user_id=user_id,
listing_id=listing_id,
listing_type=body.listing_type,
decision=body.decision,
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
return _to_response(result)
@decision_router.get("", response_model=list[DecisionResponse])
async def get_decisions(
user: Annotated[User, Depends(get_current_user)],
) -> list[DecisionResponse]:
"""Get all decisions for the current user."""
user_id = _get_user_id(user)
repo = DecisionRepository(engine)
decisions = decision_service.get_user_decisions(repo, user_id)
return [_to_response(d) for d in decisions]
@decision_router.delete("/{listing_id}")
async def delete_decision(
user: Annotated[User, Depends(get_current_user)],
listing_id: int,
listing_type: str = Query(..., description="RENT or BUY"),
) -> dict[str, bool]:
"""Remove a decision (un-like/un-dislike)."""
user_id = _get_user_id(user)
repo = DecisionRepository(engine)
try:
deleted = decision_service.remove_decision(
repo, user_id, listing_id, listing_type
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
if not deleted:
raise HTTPException(status_code=404, detail="Decision not found")
return {"success": True}