fix: FF calendar upload endpoint + path resolution for server deployment
- Add POST /api/eco/ff-upload to receive CSV from browser (saves to /tmp) - _find_csv() checks /tmp, /app, project root — works local + Docker - _run_ff_import now takes explicit csv_path parameter - Frontend: Upload CSV button (file input) → uploads to server first, then Import into DB — with upload progress messages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@ import logging
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, HTTPException, Query
|
||||
from fastapi import APIRouter, BackgroundTasks, File, HTTPException, Query, UploadFile
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/api/eco", tags=["Economic Calendar"])
|
||||
@@ -296,17 +296,27 @@ def upcoming_events() -> List[Dict[str, Any]]:
|
||||
_ff_import_status: Dict[str, Any] = {"running": False, "last_result": None}
|
||||
_ff_sync_status: Dict[str, Any] = {"running": False, "last_result": None}
|
||||
|
||||
_FF_CSV_PATH = os.path.join(
|
||||
os.path.dirname(__file__), "..", "..", "forex_factory_cache.csv"
|
||||
)
|
||||
# CSV may sit at project root (local dev) or in /tmp (uploaded via browser on server)
|
||||
_FF_CSV_CANDIDATES = [
|
||||
"/tmp/forex_factory_cache.csv",
|
||||
os.path.join(os.path.dirname(__file__), "..", "forex_factory_cache.csv"),
|
||||
os.path.join(os.path.dirname(__file__), "..", "..", "forex_factory_cache.csv"),
|
||||
]
|
||||
|
||||
|
||||
def _run_ff_import():
|
||||
def _find_csv() -> str | None:
|
||||
for p in _FF_CSV_CANDIDATES:
|
||||
full = os.path.abspath(p)
|
||||
if os.path.exists(full):
|
||||
return full
|
||||
return None
|
||||
|
||||
|
||||
def _run_ff_import(csv_path: str):
|
||||
global _ff_import_status
|
||||
_ff_import_status["running"] = True
|
||||
try:
|
||||
from services.ff_calendar import import_csv
|
||||
csv_path = os.path.abspath(_FF_CSV_PATH)
|
||||
result = import_csv(csv_path)
|
||||
_ff_import_status["last_result"] = result
|
||||
except Exception as e:
|
||||
@@ -330,15 +340,30 @@ def _run_ff_sync():
|
||||
_ff_sync_status["running"] = False
|
||||
|
||||
|
||||
@router.post("/ff-upload")
|
||||
async def ff_upload(file: UploadFile = File(...)) -> Dict[str, Any]:
|
||||
"""Upload forex_factory_cache.csv directly from the browser (saves to /tmp)."""
|
||||
dest = "/tmp/forex_factory_cache.csv"
|
||||
try:
|
||||
content = await file.read()
|
||||
with open(dest, "wb") as f:
|
||||
f.write(content)
|
||||
size_mb = round(len(content) / 1_048_576, 1)
|
||||
print(f"[FF upload] Saved {size_mb} MB to {dest}", flush=True)
|
||||
return {"status": "uploaded", "path": dest, "size_mb": size_mb}
|
||||
except Exception as e:
|
||||
raise HTTPException(500, f"Upload failed: {e}")
|
||||
|
||||
|
||||
@router.post("/ff-import")
|
||||
def ff_import(background_tasks: BackgroundTasks) -> Dict[str, Any]:
|
||||
"""Import forex_factory_cache.csv into ff_calendar table (background)."""
|
||||
if _ff_import_status["running"]:
|
||||
raise HTTPException(409, "Import already running")
|
||||
csv_path = os.path.abspath(_FF_CSV_PATH)
|
||||
if not os.path.exists(csv_path):
|
||||
raise HTTPException(404, f"CSV not found: {csv_path}")
|
||||
background_tasks.add_task(_run_ff_import)
|
||||
csv_path = _find_csv()
|
||||
if not csv_path:
|
||||
raise HTTPException(404, "CSV not found. Upload it first via POST /api/eco/ff-upload")
|
||||
background_tasks.add_task(_run_ff_import, csv_path)
|
||||
return {"status": "started", "csv": csv_path}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user