diff --git a/terraso_backend/apps/core/views.py b/terraso_backend/apps/core/views.py index c7ef10790..7410f299b 100644 --- a/terraso_backend/apps/core/views.py +++ b/terraso_backend/apps/core/views.py @@ -53,7 +53,7 @@ def post(self, request, **kwargs): geojson = parse_file_to_geojson(file) except ValueError as error: return JsonResponse( - {"errors": [{"message": json.dumps([{"code": error.message}])}]}, status=400 + {"errors": [{"message": json.dumps([{"code": str(error)}])}]}, status=400 ) return JsonResponse({"geojson": geojson}) diff --git a/terraso_backend/apps/graphql/schema/data_entries.py b/terraso_backend/apps/graphql/schema/data_entries.py index dac22bd65..0ad4a770b 100644 --- a/terraso_backend/apps/graphql/schema/data_entries.py +++ b/terraso_backend/apps/graphql/schema/data_entries.py @@ -124,7 +124,7 @@ def resolve_url(self, info): def resolve_geojson(self, info): if f".{self.resource_type}" not in settings.DATA_ENTRY_GIS_TYPES.keys(): return None - file = data_entry_upload_service.get_file(self.s3_object_name, "rt") + file = data_entry_upload_service.get_file(self.s3_object_name, "rb") try: return parse_file_to_geojson(file) except ValueError: diff --git a/terraso_backend/apps/shared_data/visualization_tileset_tasks.py b/terraso_backend/apps/shared_data/visualization_tileset_tasks.py index ecd439c34..b5bba752f 100644 --- a/terraso_backend/apps/shared_data/visualization_tileset_tasks.py +++ b/terraso_backend/apps/shared_data/visualization_tileset_tasks.py @@ -132,7 +132,7 @@ def _get_geojson_from_dataset(data_entry, visualization): def _get_geojson_from_gis(data_entry): - file = data_entry_upload_service.get_file(data_entry.s3_object_name, "rt") + file = data_entry_upload_service.get_file(data_entry.s3_object_name, "rb") return parse_file_to_geojson(file) diff --git a/terraso_backend/tests/graphql/conftest.py b/terraso_backend/tests/graphql/conftest.py index 4fadd787d..02478a8a5 100644 --- a/terraso_backend/tests/graphql/conftest.py +++ b/terraso_backend/tests/graphql/conftest.py @@ -333,6 +333,21 @@ def data_entry_kml(users, groups): ) +@pytest.fixture +def data_entry_shapefile(users, groups): + creator = users[0] + creator_group = groups[0] + creator_group.members.add(creator) + return mixer.blend( + DataEntry, + created_by=creator, + size=100, + groups=creator_group, + entry_type=DataEntry.ENTRY_TYPE_FILE, + resource_type="zip", + ) + + @pytest.fixture def visualization_config_current_user(users, data_entry_current_user_file, groups): creator = users[0] diff --git a/terraso_backend/tests/graphql/test_shared_data.py b/terraso_backend/tests/graphql/test_shared_data.py index 059a54126..73223ec5b 100644 --- a/terraso_backend/tests/graphql/test_shared_data.py +++ b/terraso_backend/tests/graphql/test_shared_data.py @@ -16,10 +16,14 @@ import json import os import tempfile +import zipfile from unittest import mock +import geopandas as gpd import pytest +from apps.core.gis.utils import DEFAULT_CRS + from ..core.gis.test_parsers import KML_CONTENT, KML_GEOJSON pytestmark = pytest.mark.django_db @@ -345,6 +349,49 @@ def test_data_entry_kml_to_geojson(get_file_mock, client_query, data_entry_kml, assert data_entry_result["geojson"] == json.dumps(KML_GEOJSON) +@mock.patch("apps.shared_data.services.data_entry_upload_service.get_file") +def test_data_entry_shapefil_to_geojson(get_file_mock, client_query, data_entry_shapefile): + gdf = gpd.GeoDataFrame({"geometry": gpd.points_from_xy([0], [0])}, crs=DEFAULT_CRS) + with tempfile.TemporaryDirectory() as tmpdir: + shapefile_zip = tempfile.NamedTemporaryFile(suffix=".zip") + shapefile_path = os.path.join(tmpdir, "test.shp") + gdf.to_file(shapefile_path) + + with zipfile.ZipFile(shapefile_zip.name, "w") as zf: + for component in ["shp", "shx", "prj"]: + zf.write(os.path.join(tmpdir, f"test.{component}"), f"test.{component}") + + with open(shapefile_zip.name, "rb") as file: + get_file_mock.return_value = file + response = client_query( + """ + {dataEntry(id: "%s") { + id + name + geojson + }} + """ + % data_entry_shapefile.id + ) + json_response = response.json() + data_entry_result = json_response["data"]["dataEntry"] + + assert data_entry_result["id"] == str(data_entry_shapefile.id) + assert data_entry_result["name"] == data_entry_shapefile.name + assert json.loads(data_entry_result["geojson"]) == { + "type": "FeatureCollection", + "features": [ + { + "id": "0", + "type": "Feature", + "properties": {}, + "geometry": {"type": "Point", "coordinates": [0.0, 0.0]}, + } + ], + "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:OGC::CRS84"}}, + } + + @mock.patch("apps.shared_data.services.data_entry_upload_service.get_file") def test_data_entry_avoid_fetching_file_for_not_gis_file(get_file_mock, client_query, data_entries): response = client_query(