From 214da391a39deb840d5667e1334de363b16ced02 Mon Sep 17 00:00:00 2001 From: spwoodcock Date: Mon, 8 Jan 2024 14:29:47 +0000 Subject: [PATCH] feat(backend): generate backmaps on project creation --- src/backend/app/projects/project_crud.py | 68 ++++++++++++++++++++-- src/backend/app/projects/project_routes.py | 36 ++++++++++++ 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/backend/app/projects/project_crud.py b/src/backend/app/projects/project_crud.py index 5d1b445471..08fed04a85 100644 --- a/src/backend/app/projects/project_crud.py +++ b/src/backend/app/projects/project_crud.py @@ -2101,22 +2101,79 @@ async def get_extracted_data_from_db(db: Session, project_id: int, outfile: str) # NOTE defined as non-async to run in separate thread -def get_project_tiles( +def init_project_basemaps( db: Session, project_id: int, background_task_id: uuid.UUID, source: str, +) -> None: + """Init basemaps for the project and task areas. + + A PMTiles archive is created for the entire project, plus + individual mbtile archives for each task area. + + Args: + db (Session): SQLAlchemy db session. + project_id (int): Associated project ID. + background_task_id (uuid.UUID): Pre-generated background task ID. + source (str): Source to use for basemap tiles. + + Returns: + None + """ + # Generate PMTiles for project area + generate_project_or_task_basemap( + db, + project_id, + background_task_id, + source, + output_format="pmtiles", + ) + + # Generate MBTiles for each task + get_tasks_async = async_to_sync(tasks_crud.get_task_id_list) + task_list = get_tasks_async(db, project_id) + + # TODO optimise to run with threadpool + for task_id in task_list: + generate_project_or_task_basemap( + db, + project_id, + background_task_id, + source, + output_format="mbtiles", + task_id=task_id, + ) + + # NOTE defined as non-async to run in separate thread def generate_project_or_task_basemap( db: Session, project_id: int, background_task_id: uuid.UUID, - source: str, + source: str = "esri", output_format: str = "pmtiles", tms: str = None, task_id: int = None, -): - """For a given project or task area, generate a basemap.""" +) -> None: + """For a given project or task area, generate a basemap. + + Wrapper that extracts the project or task bbox prior to calling + generate_basemap_for_bbox function. + + Args: + db (Session): SQLAlchemy db session. + project_id (int): ID of project to create tiles for. + background_task_id (uuid.UUID): UUID of background task to track. + source (str): Tile source ("esri", "bing", "topo", "google", "oam"). + output_format (str, optional): Default "mbtiles". + Other options: "pmtiles", "sqlite3". + tms (str, optional): Default None. Custom TMS provider URL. + task_id (bool): If set, create for a task boundary only. + + Returns: + None + """ if not task_id: # Project Outline log.debug(f"Getting bbox for project: {project_id}") @@ -2163,11 +2220,12 @@ def generate_basemap_for_bbox( tms: str = None, task_id: int = None, ): - """Get basemap tiles for a project. + """Get basemap tiles for a given bounding box. Args: db (Session): SQLAlchemy db session. project_id (int): ID of project to create tiles for. + bbox (tuple): the bounding box for generate for. background_task_id (uuid.UUID): UUID of background task to track. source (str): Tile source ("esri", "bing", "topo", "google", "oam"). output_format (str, optional): Default "mbtiles". diff --git a/src/backend/app/projects/project_routes.py b/src/backend/app/projects/project_routes.py index 5e3c0dccdd..b798eae234 100644 --- a/src/backend/app/projects/project_routes.py +++ b/src/backend/app/projects/project_routes.py @@ -1044,6 +1044,42 @@ async def generate_project_tiles( return JSONResponse(status_code=200, content={"success": True}) +@router.get("/tiles/{project_id}/init") +async def init_project_tiles( + background_tasks: BackgroundTasks, + project_id: int, + source: str = Query( + ..., description="Select a source for tiles", enum=TILES_SOURCE + ), + db: Session = Depends(database.get_db), +): + """Init all basemaps for a project, optional on project creation. + + Args: + project_id (int): ID of project to create tiles for. + source (str): Tile source ("esri", "bing", "topo", "google", "oam"). + + Returns: + dict: Success message that tile generation started. + """ + # Create task in db and return uuid + log.debug( + f"Creating init_project_tiles background task for project ID: {project_id}" + ) + background_task_id = await project_crud.insert_background_task_into_database( + db, name="init tiles", project_id=project_id + ) + + background_tasks.add_task( + project_crud.init_project_basemaps, + db, + project_id, + background_task_id, + source, + ) + + return JSONResponse(status_code=200, content={"success": True}) + @router.get("/tiles_list/{project_id}/") async def tiles_list(project_id: int, db: Session = Depends(database.get_db)):