Skip to content

Commit

Permalink
Merge pull request #2478 from onaio/fix-geotrace-bug-with-repeats
Browse files Browse the repository at this point in the history
Ensure geotrace and geoshape in repeats is included in GeoJSON data endpoint
  • Loading branch information
KipSigei authored Sep 25, 2023
2 parents 0cf521e + f1b3470 commit e98a41a
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 5 deletions.
131 changes: 131 additions & 0 deletions onadata/apps/api/tests/viewsets/test_data_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,137 @@ def test_geojson_format(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data, data)

def test_geotraces_in_repeats(self):
# publish sample geotrace submissions
md = """
| survey |
| | type | name | label | required | calculation |
| | begin repeat | segment | Waterway trace | | |
| | calculate | point_position | | | position(..)|
| | geotrace | blueline | GPS Coordinates | yes | |
| | end repeat |
"""
self.xform = self._publish_markdown(
md, self.user, self.project, id_string="geotraces")
# publish submissions
self._publish_submit_geoms_in_repeats("Geotraces")
view = DataViewSet.as_view({"get": "list"})
request = self.factory.get("/", **self.extra)
response = view(request, pk=self.xform.pk, format="geojson")
self.assertEqual(response.status_code, 200)
# get geojson from geo_field
data_get = {"geo_field": "segment/blueline"}
request = self.factory.get("/", data=data_get, **self.extra)
response = view(request, pk=self.xform.pk, format="geojson")
instances = self.xform.instances.all().order_by("id")
self.assertEqual(response.status_code, 200)
self.assertEqual(self.xform.instances.count(), 2)
self.assertEqual(len(response.data["features"]), 2)
self.assertEqual(self.xform.geotrace_xpaths(), ["segment/blueline"])
# test LineString geojson format
data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[36.790503, -1.283987],
[36.77264, -1.268026],
[36.79411, -1.266191],
[36.790757, -1.283009],
],
},
"properties": {"id": instances[0].pk, "xform": self.xform.pk},
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[36.809057, -1.269392],
[36.803303, -1.271966],
[36.805943, -1.268118],
[36.808822, -1.269405],
],
},
"properties": {"id": instances[1].pk, "xform": self.xform.pk},
},
],
}
self.assertEqual(response.data, data)

def test_geoshapes_in_repeats(self):
# publish sample geoshape submissions
md = """
| survey |
| | type | name | label | required | calculation |
| | begin repeat | segment | Waterway trace | | |
| | calculate | point_position | | | position(..)|
| | geoshape | blueline | GPS Coordinates | yes | |
| | end repeat |
"""
self.xform = self._publish_markdown(
md, self.user, self.project, id_string="geoshapes")
# publish submissions
self._publish_submit_geoms_in_repeats("Geoshapes")
view = DataViewSet.as_view({"get": "list"})
request = self.factory.get("/", **self.extra)
response = view(request, pk=self.xform.pk, format="geojson")
self.assertEqual(response.status_code, 200)
# get geojson from specific field
data_get = {"geo_field": "segment/blueline"}
request = self.factory.get("/", data=data_get, **self.extra)
response = view(request, pk=self.xform.pk, format="geojson")
instances = self.xform.instances.all().order_by("id")
self.assertEqual(response.status_code, 200)
self.assertEqual(self.xform.instances.count(), 2)
self.assertEqual(len(response.data["features"]), 2)
self.assertEqual(self.xform.polygon_xpaths(), ["segment/blueline"])
# test Polygon geojson format
data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[36.788843, -1.297323],
[36.799246, -1.292646],
[36.797564, -1.299639],
[36.789099, -1.297537],
[36.794943, -1.296379],
[36.797134, -1.299167],
[36.788843, -1.297323],
]
],
},
"properties": {"id": instances[0].pk, "xform": self.xform.pk},
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[36.79198, -1.29728],
[36.785793, -1.298009],
[36.789744, -1.29961],
[36.790625, -1.300146],
[36.792107, -1.300897],
[36.79198, -1.29728],
]
],
},
"properties": {"id": instances[1].pk, "xform": self.xform.pk},
},
],
}
self.assertEqual(response.data, data)

def test_instances_with_geopoints(self):
# publish sample geo submissions
self._publish_submit_geojson()
Expand Down
3 changes: 3 additions & 0 deletions onadata/apps/main/tests/fixtures/geolocation/Geoshapes.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
today,start,end,deviceid,segment[1]/point_position,segment[1]/blueline,segment[2]/point_position,segment[2]/blueline,meta/instanceID,_id,_uuid,_submission_time,_date_modified,_tags,_notes,_version,_duration,_submitted_by,_total_media,_media_count,_media_all_received,_xform_id
2023-09-15,2023-09-15T12:53:19.451+03:00,2023-09-15T12:55:10.386+03:00,enketo.ona.io:qrggmjketRepjz8x,1,-1.297323 36.788843 0 0;-1.292646 36.799246 0 0;-1.299639 36.797564 0 0;-1.297537 36.789099 2 3;-1.296379 36.794943 0 0;-1.299167 36.797134 0 0;-1.297323 36.788843 0 0,n/a,n/a,uuid:cb2f1dae-47f2-4919-9fea-5ede2fda841c,122094074,cb2f1dae-47f2-4919-9fea-5ede2fda841c,2023-09-15T09:55:11,2023-09-15T09:55:11,,,202309150951,111.0,kipsigei,0,0,True,764655
2023-09-15,2023-09-15T12:55:10.436+03:00,2023-09-15T12:55:37.212+03:00,enketo.ona.io:qrggmjketRepjz8x,1,-1.29728 36.79198 0 0;-1.298009 36.785793 0 0;-1.29961 36.789744 0 0;-1.300146 36.790625 0 0;-1.300897 36.792107 0 0;-1.29728 36.79198 0 0,2,-1.297391 36.789659 0 0;-1.298163 36.78296 0 0;-1.299751 36.7882 0 0;-1.297391 36.789659 0 0,uuid:6ac3e33c-d064-45e0-8597-880227e36435,122094094,6ac3e33c-d064-45e0-8597-880227e36435,2023-09-15T09:55:37,2023-09-15T09:55:37,,,202309150951,27.0,kipsigei,0,0,True,764655
3 changes: 3 additions & 0 deletions onadata/apps/main/tests/fixtures/geolocation/Geotraces.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
today,start,end,deviceid,segment[1]/point_position,segment[1]/blueline,segment[2]/point_position,segment[2]/blueline,meta/instanceID,_id,_uuid,_submission_time,_date_modified,_tags,_notes,_version,_duration,_submitted_by,_total_media,_media_count,_media_all_received,_xform_id
2023-09-15,2023-09-15T12:39:32.676+03:00,2023-09-15T12:39:52.828+03:00,enketo.ona.io:qrggmjketRepjz8x,1,-1.283987 36.790503 0 0;-1.268026 36.77264 0 0;-1.266191 36.79411 0 0;-1.283009 36.790757 2 2,n/a,n/a,uuid:51558e36-de1c-49c1-bf66-199060b2655b,122093541,51558e36-de1c-49c1-bf66-199060b2655b,2023-09-15T09:39:53,2023-09-15T09:39:53,,,202309150939,20.0,kipsigei,0,0,True,764649
2023-09-15,2023-09-15T12:39:52.858+03:00,2023-09-15T12:40:31.290+03:00,enketo.ona.io:qrggmjketRepjz8x,1,-1.269392 36.809057 0 0;-1.271966 36.803303 0 0;-1.268118 36.805943 0 0;-1.269405 36.808822 0 0,2,-1.25616 36.865203 0 0;-1.251569 36.86919 0 0;-1.255495 36.870234 0 0;-1.256203 36.8654 0 0,uuid:39c3ee3f-bab3-4fca-81ce-011c6f26eb98,122093563,39c3ee3f-bab3-4fca-81ce-011c6f26eb98,2023-09-15T09:40:32,2023-09-15T09:40:32,,,202309150939,39.0,kipsigei,0,0,True,764649
19 changes: 19 additions & 0 deletions onadata/apps/main/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,25 @@ def _publish_submit_geojson(self, has_empty_geoms=False, only_geopoints=False):
response = view(request, pk=self.xform.id)
self.assertEqual(response.status_code, 200)

def _publish_submit_geoms_in_repeats(self, geom_type):
view = XFormViewSet.as_view({"post": "csv_import"})
with open(
os.path.join(
settings.PROJECT_ROOT,
"apps",
"main",
"tests",
"fixtures",
"geolocation",
f"{geom_type}.csv",
),
encoding="utf-8",
) as csv_import:
post_data = {"csv_file": csv_import}
request = self.factory.post("/", data=post_data, **self.extra)
response = view(request, pk=self.xform.id)
self.assertEqual(response.status_code, 200)

def _publish_markdown(self, md_xlsform, user, project=None, **kwargs):
"""
Publishes a markdown XLSForm.
Expand Down
18 changes: 13 additions & 5 deletions onadata/libs/serializers/geojson_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from onadata.apps.logger.models.instance import Instance
from onadata.libs.utils.common_tools import str_to_bool
from onadata.libs.utils.dict_tools import get_values_matching_key


def create_feature(instance, geo_field, fields):
Expand Down Expand Up @@ -65,7 +66,6 @@ def geometry_from_string(points, simple_style):
`simple_style` param allows building geojson
that adheres to the simplestyle-spec
"""

points = points.split(";")
pnt_list = [tuple(map(float, reversed(point.split()[:2]))) for point in points]

Expand Down Expand Up @@ -126,17 +126,25 @@ def to_representation(self, instance):
geo_field = request.query_params.get("geo_field")
simple_style = request.query_params.get("simple_style")
title = request.query_params.get("title")

if fields:
for field in fields.split(","):
ret["properties"][field] = instance.json.get(field)

if geo_field:
xform = instance.xform
geotrace_xpaths = xform.geotrace_xpaths()
polygon_xpaths = xform.polygon_xpaths()
if "properties" in ret:
if title:
ret["properties"]["title"] = instance.json.get(title)
if fields:
for field in fields.split(","):
ret["properties"][field] = instance.json.get(field)
points = instance.json.get(geo_field)
if geo_field in geotrace_xpaths or geo_field in polygon_xpaths:
value = get_values_matching_key(instance.json, geo_field)
points = next(value)
geometry = (
geometry_from_string(points, simple_style)
if points
if points and isinstance(points, str)
else None
)

Expand Down

0 comments on commit e98a41a

Please sign in to comment.