Phase 2.1: Card mirror system for deckbuilding features

- Created MtgCardMirror and DeckCardLink models in mirror_models.py
- Created card_mirror_service.py with sync_mirrors functionality
- Added sync_mirrors() method to mtgjson_manager.py
- Added mirror_get_db() dependency to database.py
- Added DecklistFile.status column (DRAUGHT/FINAL)
- Updated DeckCreate schema with status field
- Added DeckWithCardsResponse schema with card_count
- Updated deck router to query card mirrors and return card counts
- Added plain text deck content support
This commit is contained in:
2026-07-22 03:35:57 +00:00
parent a01e33eb5e
commit 2c74a107bc
9 changed files with 744 additions and 70 deletions
+65 -1
View File
@@ -4,7 +4,7 @@ Pydantic schemas for request/response validation.
Provides typed data structures for API endpoints.
"""
from pydantic import BaseModel, EmailStr, Field
from typing import Optional, List
from typing import Optional, List, Dict
from datetime import datetime
@@ -95,6 +95,7 @@ class DeckCreate(BaseModel):
content: str = Field(..., min_length=1)
folder_id: Optional[int] = None
format: str = Field("native", pattern="^(native|plain)$")
status: str = Field("DRAUGHT", pattern="^(DRAUGHT|FINAL)$")
class DeckUpdate(BaseModel):
@@ -102,6 +103,7 @@ class DeckUpdate(BaseModel):
name: Optional[str] = None
content: Optional[str] = None
folder_id: Optional[int] = None
status: Optional[str] = Field(None, pattern="^(DRAUGHT|FINAL)$")
class DeckResponse(BaseModel):
@@ -110,6 +112,7 @@ class DeckResponse(BaseModel):
name: str
content: str
format: str
status: str
folder_id: Optional[int]
owner_id: int
creation_date: datetime
@@ -228,3 +231,64 @@ class PaginatedResponse(BaseModel):
page: int
page_size: int
total_pages: int
# ===== Card Mirror Schemas =====
class CardMirrorResponse(BaseModel):
"""Mirrored card data for user decks."""
id: int
source_id: Optional[int]
name: str
mana_cost: Optional[str]
type_line: Optional[str]
oracle_text: Optional[str]
power: Optional[str]
toughness: Optional[str]
rarity: Optional[str]
layout: Optional[str]
artist: Optional[str]
flavor_text: Optional[str]
numbers: Optional[str]
identifiers: Optional[str] # JSON string
images: Optional[str] # JSON string
image: Optional[str]
card_parts: Optional[str]
keywords: Optional[str]
legalities: Optional[str] # JSON string
set_code: Optional[str]
set_name: Optional[str]
synced_at: Optional[datetime]
created_at: datetime
class Config:
from_attributes = True
class DeckCardLinkResponse(BaseModel):
"""Deck-card link response."""
id: int
deck_id: int
card_id: int
quantity: int
zone: str
card: CardMirrorResponse
class Config:
from_attributes = True
class DeckWithCardsResponse(BaseModel):
"""Deck response with card links."""
id: int
name: str
content: str
format: str
status: str
folder_id: Optional[int]
owner_id: int
creation_date: datetime
card_links: List[DeckCardLinkResponse] = []
class Config:
from_attributes = True