Final project commit: MTGJSON data integration and backend API
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Fix MTG sets endpoint - File-based changes only.
|
||||
|
||||
This script:
|
||||
1. Reorders routes in card_router.py so /sets comes before /{card_name}
|
||||
2. Adds image_url column to MtgSet model
|
||||
3. Updates service layer to return image_url
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def fix_route_ordering():
|
||||
"""Reorder routes in card_router.py so /sets comes before /{card_name}."""
|
||||
route_file = Path('/home/wall-o/projects/mtgonline/backend/app/routers/card_router.py')
|
||||
content = route_file.read_text()
|
||||
|
||||
# Find the current route order
|
||||
# The issue: /{card_name} is defined before /sets
|
||||
# We need to move /sets and /sets/{set_code} before /{card_name}
|
||||
|
||||
# Current order (problematic):
|
||||
# 1. /search
|
||||
# 2. /{card_name}
|
||||
# 3. /set/{set_code}
|
||||
# 4. /types
|
||||
# 5. /rarities
|
||||
# 6. /sets
|
||||
# 7. /sets/{set_code}
|
||||
# 8. /statistics
|
||||
|
||||
# New order (correct):
|
||||
# 1. /search
|
||||
# 2. /set/{set_code}
|
||||
# 3. /types
|
||||
# 4. /rarities
|
||||
# 5. /sets
|
||||
# 6. /sets/{set_code}
|
||||
# 7. /statistics
|
||||
# 8. /{card_name} (wildcard last)
|
||||
|
||||
# Extract route blocks using regex
|
||||
# Pattern to find decorator + function
|
||||
pattern = r'(@router\.\w+\([^)]+\)\s*\nasync def \w+.*?)(?=@router\.\w+\(|$)'
|
||||
|
||||
matches = re.findall(pattern, content, re.DOTALL)
|
||||
|
||||
# Identify each route
|
||||
routes = {}
|
||||
for match in matches:
|
||||
# Extract route path
|
||||
route_match = re.search(r'@router\.(\w+)\(([^)]+)\)', match)
|
||||
if route_match:
|
||||
method = route_match.group(1)
|
||||
args = route_match.group(2)
|
||||
routes[f"{method}:{args}"] = match
|
||||
|
||||
print("Current routes:")
|
||||
for key in routes:
|
||||
print(f" {key}")
|
||||
|
||||
# Define the correct order
|
||||
correct_order = [
|
||||
"get:/search",
|
||||
"get:/set/{set_code}",
|
||||
"get:/types",
|
||||
"get:/rarities",
|
||||
"get:/sets",
|
||||
"get:/sets/{set_code}",
|
||||
"get:/statistics",
|
||||
"get:/{card_name}",
|
||||
]
|
||||
|
||||
# Verify all routes are present
|
||||
for route_key in correct_order:
|
||||
if route_key not in routes:
|
||||
print(f"✗ Missing route: {route_key}")
|
||||
return False
|
||||
|
||||
print("✓ All routes found")
|
||||
|
||||
# Rebuild the file content
|
||||
new_content = content[:content.index('@router.get("/search")')]
|
||||
|
||||
for route_key in correct_order:
|
||||
new_content += routes[route_key]
|
||||
|
||||
# Add the router variable
|
||||
new_content += "\n\nrouter = APIRouter(prefix=\"/mtg/cards\", tags=[\"MTG Cards\"])\n"
|
||||
|
||||
route_file.write_text(new_content)
|
||||
print("✓ Routes reordered")
|
||||
|
||||
|
||||
def update_mtg_set_model():
|
||||
"""Update MtgSet model to include image_url."""
|
||||
model_file = Path('/home/wall-o/projects/mtgonline/backend/app/models/mtg_models.py')
|
||||
content = model_file.read_text()
|
||||
|
||||
# Add image_url column after mtgo_code
|
||||
if 'image_url' in content:
|
||||
print("✓ image_url already in MtgSet model")
|
||||
return
|
||||
|
||||
# Find the Mtgo_code line
|
||||
insert_point = "mtgo_code = Column(String(10), nullable=True)"
|
||||
new_column = '\n image_url = Column(Text, nullable=True)'
|
||||
|
||||
content = content.replace(insert_point, insert_point + new_column)
|
||||
model_file.write_text(content)
|
||||
print("✓ image_url added to MtgSet model")
|
||||
|
||||
|
||||
def update_service_layer():
|
||||
"""Update service layer to return image_url."""
|
||||
service_file = Path('/home/wall-o/projects/mtgonline/backend/app/services/card_database.py')
|
||||
content = service_file.read_text()
|
||||
|
||||
if 'image_url' not in content:
|
||||
# Update get_sets() function
|
||||
old_get_sets = ''' stmt = select(MtgSet).order_by(MtgSet.release_date.desc())
|
||||
result = await db.execute(stmt)
|
||||
rows = result.fetchall()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": s.id,
|
||||
"code": s.code,
|
||||
"name": s.name,
|
||||
"release_date": s.release_date.isoformat() if s.release_date else None,
|
||||
"total_size": s.total_size,
|
||||
"base_set_size": s.base_set_size,
|
||||
}
|
||||
for s in rows
|
||||
]'''
|
||||
|
||||
new_get_sets = ''' stmt = select(MtgSet).order_by(MtgSet.release_date.desc())
|
||||
result = await db.execute(stmt)
|
||||
rows = result.fetchall()
|
||||
|
||||
return [
|
||||
{
|
||||
"id": s.id,
|
||||
"code": s.code,
|
||||
"name": s.name,
|
||||
"release_date": s.release_date.isoformat() if s.release_date else None,
|
||||
"total_size": s.total_size,
|
||||
"base_set_size": s.base_set_size,
|
||||
"image_url": s.image_url,
|
||||
}
|
||||
for s in rows
|
||||
]'''
|
||||
|
||||
if old_get_sets in content:
|
||||
content = content.replace(old_get_sets, new_get_sets)
|
||||
print("✓ Updated get_sets() to include image_url")
|
||||
|
||||
# Update get_set_by_code() function
|
||||
old_get_by_code = ''' return {
|
||||
"id": mtg_set.id,
|
||||
"code": mtg_set.code,
|
||||
"name": mtg_set.name,
|
||||
"type": mtg_set.type,
|
||||
"release_date": mtg_set.release_date.isoformat() if mtg_set.release_date else None,
|
||||
"base_set_size": mtg_set.base_set_size,
|
||||
"total_size": mtg_set.total_size,
|
||||
"is_foil_only": mtg_set.is_foil_only,
|
||||
"is_non_foil_only": mtg_set.is_non_foil_only,
|
||||
"digital": mtg_set.digital,
|
||||
"icon_svg_url": mtg_set.icon_svg_url,
|
||||
"parent_code": mtg_set.parent_code,
|
||||
"mtgo_code": mtg_set.mtgo_code,
|
||||
}'''
|
||||
|
||||
new_get_by_code = ''' return {
|
||||
"id": mtg_set.id,
|
||||
"code": mtg_set.code,
|
||||
"name": mtg_set.name,
|
||||
"type": mtg_set.type,
|
||||
"release_date": mtg_set.release_date.isoformat() if mtg_set.release_date else None,
|
||||
"base_set_size": mtg_set.base_set_size,
|
||||
"total_size": mtg_set.total_size,
|
||||
"is_foil_only": mtg_set.is_foil_only,
|
||||
"is_non_foil_only": mtg_set.is_non_foil_only,
|
||||
"digital": mtg_set.digital,
|
||||
"icon_svg_url": mtg_set.icon_svg_url,
|
||||
"parent_code": mtg_set.parent_code,
|
||||
"mtgo_code": mtg_set.mtgo_code,
|
||||
"image_url": mtg_set.image_url,
|
||||
}'''
|
||||
|
||||
if old_get_by_code in content:
|
||||
content = content.replace(old_get_by_code, new_get_by_code)
|
||||
print("✓ Updated get_set_by_code() to include image_url")
|
||||
|
||||
service_file.write_text(content)
|
||||
|
||||
|
||||
def main():
|
||||
"""Run all file-based fixes."""
|
||||
print("=== MTG SETS ENDPOINT FIX (FILE CHANGES) ===\n")
|
||||
|
||||
# 1. Fix route ordering
|
||||
print("1. Route Reordering")
|
||||
fix_route_ordering()
|
||||
print()
|
||||
|
||||
# 2. Update model
|
||||
print("2. Model Update")
|
||||
update_mtg_set_model()
|
||||
print()
|
||||
|
||||
# 3. Update service layer
|
||||
print("3. Service Layer Update")
|
||||
update_service_layer()
|
||||
print()
|
||||
|
||||
print("=== FILE CHANGES COMPLETE ===")
|
||||
print("\nNext steps:")
|
||||
print("1. Add image_url column to mtg_sets table in database")
|
||||
print("2. Restart the backend Docker container")
|
||||
print("3. Test /api/mtg/cards/sets endpoint")
|
||||
print("4. Run refresh_mtg.py to populate image_url data")
|
||||
print("5. Test /api/mtg/cards/sets/{set_code} endpoint")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user