from fastapi import FastAPI, File, UploadFile from fastapi.responses import FileResponse, PlainTextResponse, JSONResponse from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel import zipfile import os import shutil from pathlib import Path from qc_validator import validate_shapefiles from verofy_uploader import upload_to_verofy app = FastAPI() # Enable CORS for frontend app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) TEMP_DIR = Path("../temp") TEMP_DIR.mkdir(exist_ok=True) class VerofyMapRequest(BaseModel): mapId: int verofyEmail: str verofyPassword: str @app.post("/upload") async def upload_shapefile(file: UploadFile = File(...)): """Handle shapefile ZIP upload and QC validation""" # Clear temp directory for item in TEMP_DIR.glob("*"): if item.is_file(): item.unlink() elif item.is_dir(): shutil.rmtree(item) # Save uploaded file zip_path = TEMP_DIR / file.filename with open(zip_path, "wb") as f: content = await file.read() f.write(content) # Unzip file try: with zipfile.ZipFile(zip_path, 'r') as zip_ref: zip_ref.extractall(TEMP_DIR) # Check if files are in a subdirectory and flatten if needed shp_files = list(TEMP_DIR.glob("*.shp")) if len(shp_files) == 0: # Look for shapefiles in subdirectories subdirs = [d for d in TEMP_DIR.iterdir() if d.is_dir()] if len(subdirs) == 1: # Move all files from subdirectory to temp root subdir = subdirs[0] for item in subdir.iterdir(): shutil.move(str(item), str(TEMP_DIR / item.name)) # Remove empty subdirectory subdir.rmdir() except Exception as e: return PlainTextResponse(f"Error extracting ZIP file: {str(e)}", status_code=400) # Run QC validation qc_result = validate_shapefiles(TEMP_DIR) if qc_result["passed"]: return {"message": "success"} else: # Generate QC report report_path = TEMP_DIR / "QC_report.txt" with open(report_path, "w") as f: f.write("QC VALIDATION FAILED\n") f.write("=" * 50 + "\n\n") for error in qc_result["errors"]: f.write(f"{error}\n") return FileResponse( path=report_path, media_type="text/plain", filename="QC_report.txt" ) @app.post("/push-to-verofy") async def push_to_verofy(request: VerofyMapRequest): """Push shapefiles from temp folder to Verofy""" # Use credentials from the request verofy_email = request.verofyEmail verofy_password = request.verofyPassword if not verofy_email or not verofy_password: return JSONResponse( status_code=400, content={ "success": False, "error": "Verofy credentials are required. Please provide your email and password." } ) # Check if temp directory has shapefiles shapefile_count = len(list(TEMP_DIR.glob("*.shp"))) if shapefile_count == 0: return JSONResponse( status_code=400, content={ "success": False, "error": "No shapefiles found in temp directory. Please upload files first." } ) # Upload to Verofy try: result = upload_to_verofy( temp_dir=str(TEMP_DIR), map_id=request.mapId, email=verofy_email, password=verofy_password, limit=None # Upload ALL records (no limit) ) if result["success"]: return JSONResponse( status_code=200, content={ "success": True, "message": "Successfully uploaded to Verofy", "uploaded": result["uploaded"], "errors": result.get("errors", []) } ) else: return JSONResponse( status_code=500, content={ "success": False, "error": "Upload to Verofy failed", "details": result.get("errors", []) } ) except Exception as e: return JSONResponse( status_code=500, content={ "success": False, "error": f"Error uploading to Verofy: {str(e)}" } ) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)