diff --git a/src/backend/app/central/central_crud.py b/src/backend/app/central/central_crud.py index 7cbdf64d8..08add5559 100644 --- a/src/backend/app/central/central_crud.py +++ b/src/backend/app/central/central_crud.py @@ -22,6 +22,7 @@ from asyncio import gather from io import BytesIO, StringIO from typing import Optional, Union +from uuid import uuid4 import geojson from fastapi import HTTPException @@ -499,14 +500,13 @@ async def convert_odk_submission_json_to_geojson( async def feature_geojson_to_entity_dict( feature: geojson.Feature, + additional_features: bool = False, ) -> central_schemas.EntityDict: """Convert a single GeoJSON to an Entity dict for upload.""" if not isinstance(feature, (dict, geojson.Feature)): log.error(f"Feature not in correct format: {feature}") raise ValueError(f"Feature not in correct format: {type(feature)}") - feature_id = feature.get("id") - geometry = feature.get("geometry", {}) if not geometry: msg = "'geometry' data field is mandatory" @@ -514,35 +514,52 @@ async def feature_geojson_to_entity_dict( raise ValueError(msg) javarosa_geom = await geojson_to_javarosa_geom(geometry) - properties = {} - for key, value in feature.get("properties", {}).items(): - if not central_schemas.is_valid_property_name(key): - log.warning(f"Invalid property name: {key},Excluding from properties.") - continue - # NOTE all properties MUST be string values for Entities, convert - properties.update({str(central_schemas.sanitize_key(key)): str(value)}) - - properties["status"] = "0" - - task_id = properties.get("task_id") - entity_label = f"Task {task_id} Feature {feature_id}" - - return {"label": entity_label, "data": {"geometry": javarosa_geom, **properties}} + raw_properties = feature.get("properties", {}) + properties = { + central_schemas.sanitize_key(key): str( + value + ) # NOTE all properties MUST be string values for Entities + for key, value in raw_properties.items() + if central_schemas.is_valid_property_name(key) + } + if additional_features: + entity_label = f"Additional Feature {uuid4()}" + else: + properties["status"] = "0" + task_id = properties.get("task_id", None) + feature_id = feature.get("id", None) + entity_label = f"Task {task_id} Feature {feature_id}" + + return { + "label": entity_label, + "data": {"geometry": javarosa_geom, **properties}, + } async def task_geojson_dict_to_entity_values( - task_geojson_dict: dict[int, geojson.Feature], + task_geojson_dict: Union[dict[int, geojson.Feature], geojson.FeatureCollection], + additional_features: bool = False, ) -> list[central_schemas.EntityDict]: """Convert a dict of task GeoJSONs into data for ODK Entity upload.""" log.debug("Converting dict of task GeoJSONs to Entity upload format") asyncio_tasks = [] - for _, geojson_dict in task_geojson_dict.items(): - # Extract the features list and pass each Feature through - features = geojson_dict.get("features", []) + + if additional_features: + features = task_geojson_dict.get("features", []) asyncio_tasks.extend( - [feature_geojson_to_entity_dict(feature) for feature in features if feature] + feature_geojson_to_entity_dict(feature, additional_features) + for feature in features + if feature ) + else: + for geojson_dict in task_geojson_dict.values(): + features = geojson_dict.get("features", []) + asyncio_tasks.extend( + feature_geojson_to_entity_dict(feature) + for feature in features + if feature + ) return await gather(*asyncio_tasks) diff --git a/src/backend/app/projects/project_routes.py b/src/backend/app/projects/project_routes.py index cd71f5fbe..812344828 100644 --- a/src/backend/app/projects/project_routes.py +++ b/src/backend/app/projects/project_routes.py @@ -70,7 +70,6 @@ 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 @@ -813,20 +812,15 @@ async def add_additional_entity_list( of the GeoJSON uploaded. """ project = project_user_dict.get("project") - project_id = project.id project_odk_id = project.odkid project_odk_creds = project.odk_credentials # NOTE the Entity name is extracted from the filename (without extension) entity_name = Path(geojson.filename).stem - # Parse geojson + divide by task - # (not technically required, but also appends properties in correct format) + # Parse geojson featcol = parse_geojson_file_to_featcol(await geojson.read()) properties = list(featcol.get("features")[0].get("properties").keys()) - feature_split_by_task = await split_geojson_by_task_areas(db, featcol, project_id) - entities_list = await central_crud.task_geojson_dict_to_entity_values( - feature_split_by_task - ) + entities_list = await central_crud.task_geojson_dict_to_entity_values(featcol, True) dataset_name = entity_name.replace(" ", "_") await central_crud.create_entity_list(