228 lines
5.8 KiB
Python
228 lines
5.8 KiB
Python
|
|
"""
|
||
|
|
Deck management routes
|
||
|
|
"""
|
||
|
|
|
||
|
|
from fastapi import APIRouter, Depends, HTTPException
|
||
|
|
from sqlalchemy.orm import Session
|
||
|
|
from pydantic import BaseModel
|
||
|
|
from typing import List, Optional
|
||
|
|
|
||
|
|
from app.database import get_db
|
||
|
|
from app.models.deck import Deck, DeckCard
|
||
|
|
from app.models.card import Card
|
||
|
|
from app.models.user import User
|
||
|
|
from app.routers.auth import get_current_user
|
||
|
|
|
||
|
|
router = APIRouter()
|
||
|
|
|
||
|
|
|
||
|
|
# Pydantic models
|
||
|
|
class DeckResponse(BaseModel):
|
||
|
|
id: int
|
||
|
|
name: str
|
||
|
|
description: Optional[str]
|
||
|
|
format: Optional[str]
|
||
|
|
game: str
|
||
|
|
is_public: bool
|
||
|
|
is_complete: bool
|
||
|
|
is_favorite: bool
|
||
|
|
total_cards: int
|
||
|
|
avg_mana_cost: Optional[float]
|
||
|
|
estimated_value: Optional[float]
|
||
|
|
commander_card_id: Optional[int]
|
||
|
|
|
||
|
|
class Config:
|
||
|
|
from_attributes = True
|
||
|
|
|
||
|
|
|
||
|
|
class DeckCreate(BaseModel):
|
||
|
|
name: str
|
||
|
|
game: str
|
||
|
|
description: Optional[str] = None
|
||
|
|
format: Optional[str] = None
|
||
|
|
is_public: bool = False
|
||
|
|
commander_card_id: Optional[int] = None
|
||
|
|
|
||
|
|
|
||
|
|
class DeckCardResponse(BaseModel):
|
||
|
|
id: int
|
||
|
|
card_id: int
|
||
|
|
card_name: str
|
||
|
|
quantity: int
|
||
|
|
is_sideboard: bool
|
||
|
|
is_commander: bool
|
||
|
|
category: Optional[str]
|
||
|
|
notes: Optional[str]
|
||
|
|
owned: bool
|
||
|
|
need_to_acquire: bool
|
||
|
|
|
||
|
|
class Config:
|
||
|
|
from_attributes = True
|
||
|
|
|
||
|
|
|
||
|
|
class DeckCardCreate(BaseModel):
|
||
|
|
card_id: int
|
||
|
|
quantity: int = 1
|
||
|
|
is_sideboard: bool = False
|
||
|
|
is_commander: bool = False
|
||
|
|
category: Optional[str] = None
|
||
|
|
notes: Optional[str] = None
|
||
|
|
|
||
|
|
|
||
|
|
# Routes
|
||
|
|
@router.get("/", response_model=List[DeckResponse])
|
||
|
|
async def get_my_decks(
|
||
|
|
current_user: User = Depends(get_current_user),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Get current user's decks"""
|
||
|
|
decks = db.query(Deck).filter(Deck.owner_id == current_user.id).all()
|
||
|
|
return decks
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/{deck_id}", response_model=DeckResponse)
|
||
|
|
async def get_deck(
|
||
|
|
deck_id: int,
|
||
|
|
current_user: User = Depends(get_current_user),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Get a specific deck"""
|
||
|
|
deck = db.query(Deck).filter(
|
||
|
|
Deck.id == deck_id,
|
||
|
|
Deck.owner_id == current_user.id
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if not deck:
|
||
|
|
raise HTTPException(status_code=404, detail="Deck not found")
|
||
|
|
|
||
|
|
return deck
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/", response_model=DeckResponse)
|
||
|
|
async def create_deck(
|
||
|
|
deck_data: DeckCreate,
|
||
|
|
current_user: User = Depends(get_current_user),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Create a new deck"""
|
||
|
|
new_deck = Deck(
|
||
|
|
**deck_data.dict(),
|
||
|
|
owner_id=current_user.id
|
||
|
|
)
|
||
|
|
|
||
|
|
db.add(new_deck)
|
||
|
|
db.commit()
|
||
|
|
db.refresh(new_deck)
|
||
|
|
|
||
|
|
return new_deck
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/{deck_id}/cards", response_model=List[DeckCardResponse])
|
||
|
|
async def get_deck_cards(
|
||
|
|
deck_id: int,
|
||
|
|
current_user: User = Depends(get_current_user),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Get all cards in a deck"""
|
||
|
|
# Verify deck ownership
|
||
|
|
deck = db.query(Deck).filter(
|
||
|
|
Deck.id == deck_id,
|
||
|
|
Deck.owner_id == current_user.id
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if not deck:
|
||
|
|
raise HTTPException(status_code=404, detail="Deck not found")
|
||
|
|
|
||
|
|
# Get deck cards with card names
|
||
|
|
cards = db.query(DeckCard, Card.name.label('card_name')).join(
|
||
|
|
Card, DeckCard.card_id == Card.id
|
||
|
|
).filter(DeckCard.deck_id == deck_id).all()
|
||
|
|
|
||
|
|
result = []
|
||
|
|
for dc, card_name in cards:
|
||
|
|
dc_dict = dc.__dict__.copy()
|
||
|
|
dc_dict['card_name'] = card_name
|
||
|
|
result.append(DeckCardResponse(**dc_dict))
|
||
|
|
|
||
|
|
return result
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("/{deck_id}/cards", response_model=DeckCardResponse)
|
||
|
|
async def add_card_to_deck(
|
||
|
|
deck_id: int,
|
||
|
|
card_data: DeckCardCreate,
|
||
|
|
current_user: User = Depends(get_current_user),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Add a card to a deck"""
|
||
|
|
# Verify deck ownership
|
||
|
|
deck = db.query(Deck).filter(
|
||
|
|
Deck.id == deck_id,
|
||
|
|
Deck.owner_id == current_user.id
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if not deck:
|
||
|
|
raise HTTPException(status_code=404, detail="Deck not found")
|
||
|
|
|
||
|
|
# Verify card exists
|
||
|
|
card = db.query(Card).filter(Card.id == card_data.card_id).first()
|
||
|
|
if not card:
|
||
|
|
raise HTTPException(status_code=404, detail="Card not found")
|
||
|
|
|
||
|
|
# Check if card already exists in deck (same sideboard status)
|
||
|
|
existing_card = db.query(DeckCard).filter(
|
||
|
|
DeckCard.deck_id == deck_id,
|
||
|
|
DeckCard.card_id == card_data.card_id,
|
||
|
|
DeckCard.is_sideboard == card_data.is_sideboard
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if existing_card:
|
||
|
|
# Update quantity if card already exists
|
||
|
|
existing_card.quantity += card_data.quantity
|
||
|
|
db.commit()
|
||
|
|
db.refresh(existing_card)
|
||
|
|
|
||
|
|
# Add card name for response
|
||
|
|
existing_card_dict = existing_card.__dict__.copy()
|
||
|
|
existing_card_dict['card_name'] = card.name
|
||
|
|
return DeckCardResponse(**existing_card_dict)
|
||
|
|
else:
|
||
|
|
# Create new deck card entry
|
||
|
|
new_deck_card = DeckCard(
|
||
|
|
deck_id=deck_id,
|
||
|
|
**card_data.dict()
|
||
|
|
)
|
||
|
|
|
||
|
|
db.add(new_deck_card)
|
||
|
|
db.commit()
|
||
|
|
db.refresh(new_deck_card)
|
||
|
|
|
||
|
|
# Recalculate deck stats
|
||
|
|
deck.calculate_stats()
|
||
|
|
db.commit()
|
||
|
|
|
||
|
|
# Add card name for response
|
||
|
|
new_card_dict = new_deck_card.__dict__.copy()
|
||
|
|
new_card_dict['card_name'] = card.name
|
||
|
|
return DeckCardResponse(**new_card_dict)
|
||
|
|
|
||
|
|
|
||
|
|
@router.put("/{deck_id}/calculate-stats")
|
||
|
|
async def calculate_deck_stats(
|
||
|
|
deck_id: int,
|
||
|
|
current_user: User = Depends(get_current_user),
|
||
|
|
db: Session = Depends(get_db)
|
||
|
|
):
|
||
|
|
"""Recalculate deck statistics"""
|
||
|
|
deck = db.query(Deck).filter(
|
||
|
|
Deck.id == deck_id,
|
||
|
|
Deck.owner_id == current_user.id
|
||
|
|
).first()
|
||
|
|
|
||
|
|
if not deck:
|
||
|
|
raise HTTPException(status_code=404, detail="Deck not found")
|
||
|
|
|
||
|
|
deck.calculate_stats()
|
||
|
|
db.commit()
|
||
|
|
|
||
|
|
return {"message": "Deck statistics updated"}
|