Files
geointel/backend/app/api/routes/exports.py
T

149 lines
6.0 KiB
Python

from __future__ import annotations
from uuid import UUID
from fastapi import APIRouter, Depends, Query, Request
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from app.api.guest_scope import assert_guest_project_scope, guest_project_scope
from app.core.errors import AppError
from app.db.session import get_db
from app.schemas import Envelope
from app.schemas.export import (
ExportContentResponse,
ExportCreateResponse,
ExportListResponse,
ExportRead,
GeoJsonExportRequest,
MapResultExportRequest,
MetadataExportRequest,
ReportExportRequest,
)
from app.services.export_service import ExportService
from app.services.dataset_service import DatasetService
from app.services.detection_service import DetectionService
from app.services.segmentation_service import SegmentationService
from app.utils.response import envelope
router = APIRouter(prefix="/exports", tags=["exports"])
@router.post("/geojson", response_model=Envelope[ExportCreateResponse])
def export_geojson(
payload: GeoJsonExportRequest,
request: Request,
db: Session = Depends(get_db),
):
if guest_project_scope(request) is not None:
if payload.export_kind in {"dataset", "vector_selection"} and payload.dataset_id is not None:
dataset = DatasetService.get_dataset(db, payload.dataset_id)
assert_guest_project_scope(request, dataset.project_id)
elif payload.export_kind == "detection_run" and payload.analysis_run_id is not None:
run = DetectionService.get_run(db, payload.analysis_run_id)
assert_guest_project_scope(request, run.project_id)
elif payload.export_kind == "segmentation_run" and payload.analysis_run_id is not None:
run = SegmentationService.get_run(db, payload.analysis_run_id)
assert_guest_project_scope(request, run.project_id)
if payload.export_kind == "vector_selection" and payload.dataset_id is not None and payload.bbox is not None:
return envelope(
ExportService.export_vector_selection_geojson(
db,
payload.dataset_id,
payload.bbox.model_dump(),
area_id=payload.area_id,
limit=payload.limit,
name=payload.name,
).model_dump(mode="json")
)
if payload.export_kind == "detection_run" and payload.analysis_run_id is not None:
return envelope(
ExportService.export_detection_run_geojson(
db,
payload.analysis_run_id,
payload.name,
intended_use=payload.intended_use,
).model_dump(mode="json")
)
if payload.export_kind == "segmentation_run" and payload.analysis_run_id is not None:
return envelope(
ExportService.export_segmentation_run_geojson(db, payload.analysis_run_id, payload.name).model_dump(mode="json")
)
if payload.dataset_id is not None:
return envelope(ExportService.export_dataset_geojson(db, payload.dataset_id, payload.name).model_dump(mode="json"))
raise AppError(
code="INVALID_EXPORT_REQUEST",
message="GeoJSON export request does not match any supported export target",
status_code=422,
)
@router.post("/metadata", response_model=Envelope[ExportCreateResponse])
def export_project_metadata(
payload: MetadataExportRequest,
request: Request,
db: Session = Depends(get_db),
):
assert_guest_project_scope(request, payload.project_id)
return envelope(ExportService.export_project_metadata(db, payload.project_id, payload.name).model_dump(mode="json"))
@router.post("/report", response_model=Envelope[ExportCreateResponse])
def export_project_report(
payload: ReportExportRequest,
request: Request,
db: Session = Depends(get_db),
):
assert_guest_project_scope(request, payload.project_id)
return envelope(ExportService.export_project_report(db, payload.project_id, payload.name).model_dump(mode="json"))
@router.post("/map-result", response_model=Envelope[ExportCreateResponse])
def export_map_result(
payload: MapResultExportRequest,
request: Request,
db: Session = Depends(get_db),
):
assert_guest_project_scope(request, payload.project_id)
return envelope(ExportService.export_map_result(db, payload).model_dump(mode="json"))
@router.get(
"/projects/{project_id}/exports",
response_model=Envelope[ExportListResponse],
)
def list_project_exports(
project_id: UUID,
request: Request,
limit: int = Query(default=50, ge=1, le=100),
offset: int = Query(default=0, ge=0),
db: Session = Depends(get_db),
):
assert_guest_project_scope(request, project_id)
return envelope(ExportService.list_project_exports(db, project_id, limit=limit, offset=offset).model_dump(mode="json"))
@router.get("/{export_id}", response_model=Envelope[ExportRead])
def get_export(export_id: UUID, request: Request, db: Session = Depends(get_db)):
export = ExportService.get_export(db, export_id)
assert_guest_project_scope(request, export.project_id)
return envelope(export.model_dump(mode="json"))
@router.get("/{export_id}/download")
def download_export(export_id: UUID, request: Request, db: Session = Depends(get_db)):
if guest_project_scope(request) is not None:
export = ExportService.get_export(db, export_id)
assert_guest_project_scope(request, export.project_id)
path = ExportService.get_export_download_path(db, export_id)
media_type = "text/html" if path.suffix.lower() in {".html", ".htm"} else "application/json"
return FileResponse(path, filename=path.name, media_type=media_type)
@router.get("/{export_id}/content", response_model=Envelope[ExportContentResponse])
def get_export_content(export_id: UUID, request: Request, db: Session = Depends(get_db)):
if guest_project_scope(request) is not None:
export = ExportService.get_export(db, export_id)
assert_guest_project_scope(request, export.project_id)
return envelope(ExportService.get_export_content(db, export_id).model_dump(mode="json"))