Skip to content

Commit

Permalink
feat(backend): add endpoint to create an entity in existing project f…
Browse files Browse the repository at this point in the history
…or new geometry (#2145)

* fix: allow users to select default odk credentials

* feat: Add endpoint to create an entity

* refactor: change endpoint name to avoid duplicate function name
  • Loading branch information
Sujanadh authored Feb 4, 2025
1 parent 9f1d4cd commit e462ece
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
28 changes: 28 additions & 0 deletions src/backend/app/central/central_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,34 @@ async def create_entity_list(
)


async def create_entity(
odk_creds: central_schemas.ODKCentralDecrypted,
odk_id: int,
properties: list[str],
entity: central_schemas.EntityDict,
dataset_name: str = "features",
) -> None:
"""Create a new Entity in ODK."""
log.info(f"Creating ODK Entity in dataset '{dataset_name}' (ODK ID: {odk_id})")
try:
properties = central_schemas.entity_fields_to_list(properties)

label = entity.get("label")
data = entity.get("data")

if not label or not data:
log.error("Missing required entity fields: 'label' or 'data'")
raise ValueError("Entity must contain 'label' and 'data' fields")

async with central_deps.get_odk_dataset(odk_creds) as odk_central:
await odk_central.createEntity(odk_id, dataset_name, label, data)
log.info(f"Entity '{label}' successfully created in ODK")

except Exception as e:
log.exception(f"Failed to create entity in ODK: {str(e)}")
raise


async def get_entities_geojson(
odk_creds: central_schemas.ODKCentralDecrypted,
odk_id: int,
Expand Down
56 changes: 55 additions & 1 deletion src/backend/app/projects/project_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import os
from io import BytesIO
from pathlib import Path
from typing import Annotated, Optional
from typing import Annotated, Any, Dict, Optional

import requests
from fastapi import (
Expand Down Expand Up @@ -69,11 +69,13 @@
DbUserRole,
)
from app.db.postgis_utils import (
add_required_geojson_properties,
check_crs,
featcol_keep_single_geom_type,
flatgeobuf_to_featcol,
merge_polygons,
parse_geojson_file_to_featcol,
split_geojson_by_task_areas,
)
from app.organisations import organisation_deps
from app.projects import project_crud, project_deps, project_schemas
Expand Down Expand Up @@ -883,6 +885,58 @@ async def add_additional_entity_list(
return Response(status_code=HTTPStatus.OK)


@router.post("/{project_id}/create-entity")
async def add_new_entity(
db: Annotated[Connection, Depends(db_conn)],
project_user_dict: Annotated[ProjectUserDict, Depends(project_manager)],
geojson: Dict[str, Any],
):
"""Create an Entity for the project in ODK."""
try:
project = project_user_dict.get("project")
project_odk_id = project.odkid
project_odk_creds = project.odk_credentials

features = geojson.get("features")
if not features or not isinstance(features, list):
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="Invalid GeoJSON format"
)

# Add required properties and extract entity data
featcol = add_required_geojson_properties(geojson)
properties = list(featcol["features"][0]["properties"].keys())
task_geojson = await split_geojson_by_task_areas(db, featcol, project.id)
entities_list = await central_crud.task_geojson_dict_to_entity_values(
task_geojson
)

if not entities_list:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="No valid entities found"
)

# Create entity in ODK
await central_crud.create_entity(
project_odk_creds,
project_odk_id,
properties=properties,
entity=entities_list[0],
dataset_name="features",
)

return Response(status_code=HTTPStatus.OK)
except HTTPException as http_err:
log.error(f"HTTP error: {http_err.detail}")
raise
except Exception as e:
log.exception("Unexpected error during entity creation")
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Entity creation failed",
) from e


@router.post("/{project_id}/generate-project-data")
async def generate_files(
db: Annotated[Connection, Depends(db_conn)],
Expand Down

0 comments on commit e462ece

Please sign in to comment.