diff --git a/openwisp_controller/geo/api/views.py b/openwisp_controller/geo/api/views.py index 8c2cedaa4..c1829b65e 100644 --- a/openwisp_controller/geo/api/views.py +++ b/openwisp_controller/geo/api/views.py @@ -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' @@ -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 ): @@ -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() diff --git a/openwisp_controller/geo/tests/test_api.py b/openwisp_controller/geo/tests/test_api.py index 9a9ba6c67..99d859dc7 100644 --- a/openwisp_controller/geo/tests/test_api.py +++ b/openwisp_controller/geo/tests/test_api.py @@ -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__) diff --git a/openwisp_controller/geo/utils.py b/openwisp_controller/geo/utils.py index a0c1e5d3a..d3e5de88c 100644 --- a/openwisp_controller/geo/utils.py +++ b/openwisp_controller/geo/utils.py @@ -41,4 +41,9 @@ def get_geo_urls(geo_views): geo_views.detail_location, name='detail_location', ), + path( + 'api/v1/controller/location//floorplan/devices/', + geo_views.device_floorplan_coordinates, + name='device_floorplan_coordinates', + ), ] diff --git a/tests/openwisp2/sample_geo/views.py b/tests/openwisp2/sample_geo/views.py index f0fc52bb0..2c2cac10d 100644 --- a/tests/openwisp2/sample_geo/views.py +++ b/tests/openwisp2/sample_geo/views.py @@ -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): @@ -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()