Initial commit of mtgonline project

This commit is contained in:
2026-07-18 04:57:40 +00:00
commit 86c12376f8
1870 changed files with 547994 additions and 0 deletions
+265
View File
@@ -0,0 +1,265 @@
"""Deck management router endpoints."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete
from typing import Optional, List
from app.core.database import get_db
from app.core.security import get_current_user
from app.models.models import DecklistFile, DecklistFolder
from app.schemas.schemas import DeckCreate, DeckUpdate, DeckResponse, FolderCreate, FolderResponse
router = APIRouter()
@router.get("/", response_model=List[DeckResponse])
async def list_decks(
folder_id: Optional[int] = None,
page: int = 1,
page_size: int = 50,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List decks for current user."""
user_id = int(current_user["user_id"])
if folder_id:
stmt = (
select(DecklistFile)
.where(
DecklistFile.owner_id == user_id,
DecklistFile.folder_id == folder_id,
)
.offset((page - 1) * page_size)
.limit(page_size)
)
else:
stmt = (
select(DecklistFile)
.where(DecklistFile.owner_id == user_id)
.offset((page - 1) * page_size)
.limit(page_size)
)
result = await db.execute(stmt)
decks = result.scalars().all()
return [DeckResponse.model_validate(deck) for deck in decks]
@router.post("/", response_model=DeckResponse)
async def create_deck(
request: DeckCreate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Create a new deck."""
user_id = int(current_user["user_id"])
# Verify folder exists if specified
if request.folder_id:
stmt = select(DecklistFolder).where(
DecklistFolder.id == request.folder_id,
DecklistFolder.owner_id == user_id,
)
result = await db.execute(stmt)
folder = result.scalar_one_or_none()
if not folder:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Folder not found",
)
new_deck = DecklistFile(
owner_id=user_id,
folder_id=request.folder_id,
name=request.name,
content=request.content,
format=request.format,
)
db.add(new_deck)
await db.flush()
return DeckResponse.model_validate(new_deck)
@router.get("/{deck_id}", response_model=DeckResponse)
async def get_deck(
deck_id: int,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Get deck by ID."""
user_id = int(current_user["user_id"])
stmt = select(DecklistFile).where(
DecklistFile.id == deck_id,
DecklistFile.owner_id == user_id,
)
result = await db.execute(stmt)
deck = result.scalar_one_or_none()
if not deck:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Deck not found",
)
return DeckResponse.model_validate(deck)
@router.patch("/{deck_id}", response_model=DeckResponse)
async def update_deck(
deck_id: int,
request: DeckUpdate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Update deck."""
user_id = int(current_user["user_id"])
stmt = select(DecklistFile).where(
DecklistFile.id == deck_id,
DecklistFile.owner_id == user_id,
)
result = await db.execute(stmt)
deck = result.scalar_one_or_none()
if not deck:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Deck not found",
)
# Update fields
update_data = request.model_dump(exclude_unset=True)
stmt = (
update(DecklistFile)
.where(DecklistFile.id == deck_id)
.values(**update_data)
)
await db.execute(stmt)
await db.flush()
# Fetch updated deck
stmt = select(DecklistFile).where(DecklistFile.id == deck_id)
result = await db.execute(stmt)
updated_deck = result.scalar_one_or_none()
return DeckResponse.model_validate(updated_deck)
@router.delete("/{deck_id}")
async def delete_deck(
deck_id: int,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Delete deck."""
user_id = int(current_user["user_id"])
stmt = select(DecklistFile).where(
DecklistFile.id == deck_id,
DecklistFile.owner_id == user_id,
)
result = await db.execute(stmt)
deck = result.scalar_one_or_none()
if not deck:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Deck not found",
)
await db.execute(delete(DecklistFile).where(DecklistFile.id == deck_id))
return {"message": "Deck deleted successfully"}
@router.get("/folders", response_model=List[FolderResponse])
async def list_folders(
parent_id: Optional[int] = None,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List folders for current user."""
user_id = int(current_user["user_id"])
if parent_id:
stmt = select(DecklistFolder).where(
DecklistFolder.parent_id == parent_id,
DecklistFolder.owner_id == user_id,
)
else:
stmt = select(DecklistFolder).where(
DecklistFolder.parent_id == None, # Top-level folders
DecklistFolder.owner_id == user_id,
)
result = await db.execute(stmt)
folders = result.scalars().all()
return [FolderResponse.model_validate(folder) for folder in folders]
@router.post("/folders", response_model=FolderResponse)
async def create_folder(
request: FolderCreate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Create a new folder."""
user_id = int(current_user["user_id"])
# Verify parent folder exists if specified
if request.parent_id:
stmt = select(DecklistFolder).where(
DecklistFolder.id == request.parent_id,
DecklistFolder.owner_id == user_id,
)
result = await db.execute(stmt)
parent_folder = result.scalar_one_or_none()
if not parent_folder:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Parent folder not found",
)
new_folder = DecklistFolder(
owner_id=user_id,
name=request.name,
parent_id=request.parent_id,
)
db.add(new_folder)
await db.flush()
return FolderResponse.model_validate(new_folder)
@router.delete("/folders/{folder_id}")
async def delete_folder(
folder_id: int,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Delete folder and all its contents."""
user_id = int(current_user["user_id"])
stmt = select(DecklistFolder).where(
DecklistFolder.id == folder_id,
DecklistFolder.owner_id == user_id,
)
result = await db.execute(stmt)
folder = result.scalar_one_or_none()
if not folder:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Folder not found",
)
# Delete folder and all decks (cascading delete)
await db.execute(delete(DecklistFolder).where(DecklistFolder.id == folder_id))
return {"message": "Folder deleted successfully"}