Skip to content

Commit

Permalink
[feature] Add API endpoint for indoor map coordinates #828
Browse files Browse the repository at this point in the history
Implemented API to return device coordinates for a given location ID.

Fixes #828
  • Loading branch information
dee077 committed Feb 2, 2025
1 parent aa08611 commit 0ccd707
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
39 changes: 39 additions & 0 deletions openwisp_controller/geo/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ class Meta(OrganizationManagedFilter.Meta):
model = FloorPlan


class DeviceFloorplanCoordinatesFilter(OrganizationManagedFilter):
class Meta(OrganizationManagedFilter.Meta):
model = Location
fields = OrganizationManagedFilter.Meta.fields + ['floorplan__floor']


class ListViewPagination(pagination.PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
Expand Down Expand Up @@ -187,6 +193,38 @@ class GeoJsonLocationList(
filterset_class = LocationOrganizationFilter


class DeviceFloorplanCoordinatesList(ProtectedAPIMixin, generics.ListAPIView):
"""
List coordinates of device floorplan for a given location ID
"""

serializer_class = DeviceLocationSerializer
pagination_class = ListViewPagination
filter_backends = [filters.DjangoFilterBackend]
filterset_class = DeviceFloorplanCoordinatesFilter
queryset = DeviceLocation.objects.select_related(
"content_object", "location", "floorplan"
)

def get_queryset(self):
location_id = self.kwargs.get('pk')
floor = self.request.query_params.get('floor')
queryset = super().get_queryset().filter(location_id=location_id)
if floor:
queryset = queryset.filter(floorplan__floor=floor)
return queryset

def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
available_floors = queryset.values_list(
'floorplan__floor', flat=True
).distinct()
return Response(
{"devices": serializer.data, "available_floors": list(available_floors)}
)


class LocationDeviceList(
FilterByParentManaged, ProtectedAPIMixin, generics.ListAPIView
):
Expand Down Expand Up @@ -239,6 +277,7 @@ class LocationDetailView(
# add with_geo filter to device API
DeviceListCreateView.filterset_class = DeviceListFilter

device_floorplan_coordinates = DeviceFloorplanCoordinatesList.as_view()
device_coordinates = DeviceCoordinatesView.as_view()
device_location = DeviceLocationView.as_view()
geojson = GeoJsonLocationList.as_view()
Expand Down
27 changes: 27 additions & 0 deletions openwisp_controller/geo/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1006,3 +1006,30 @@ def test_deactivated_device(self):
with self.subTest('Test deleting DeviceLocation'):
response = self.client.delete(url)
self.assertEqual(response.status_code, 403)

def test_floorplan_coordinates(self):
org = self._create_org()
location = self._create_location(type='indoor', organization=org)
floor1 = self._create_floorplan(floor=1, location=location)
floor2 = self._create_floorplan(floor=2, location=location)
device1 = self._create_device(
name='device1', mac_address='00:00:00:00:00:01', organization=org
)
device2 = self._create_device(
name='device2', mac_address='00:00:00:00:00:02', organization=org
)
self._create_object_location(
content_object=device1,
location=location,
floorplan=floor1,
organization=org,
)
self._create_object_location(
content_object=device2,
location=location,
floorplan=floor2,
organization=org,
)
path = reverse('geo_api:device_floorplan_coordinates', args=[location.id])
response = self.client.get(path)
print(response.__dict__)
5 changes: 5 additions & 0 deletions openwisp_controller/geo/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ def get_geo_urls(geo_views):
geo_views.detail_location,
name='detail_location',
),
path(
'api/v1/controller/location/<str:pk>/floorplan/devices/',
geo_views.device_floorplan_coordinates,
name='device_floorplan_coordinates',
),
]
6 changes: 6 additions & 0 deletions tests/openwisp2/sample_geo/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
from openwisp_controller.geo.api.views import (
LocationListCreateView as BaseLocationListCreateView,
)
from openwisp_controller.geo.api.views import (
DeviceFloorplanCoordinatesList as BaseDeviceFloorplanCoordinatesList,
)


class DeviceCoordinatesView(BaseDeviceCoordinatesView):
Expand Down Expand Up @@ -55,7 +58,10 @@ class LocationListCreateView(BaseLocationListCreateView):
class LocationDetailView(BaseLocationDetailView):
pass

class DeviceFloorplanCoordinatesList(BaseDeviceFloorplanCoordinatesList):
pass

device_floorplan_coordinates = DeviceFloorplanCoordinatesList.as_view()
device_coordinates = DeviceCoordinatesView.as_view()
device_location = DeviceLocationView.as_view()
geojson = GeoJsonLocationList.as_view()
Expand Down

0 comments on commit 0ccd707

Please sign in to comment.