Skip to content

Commit 545dddb

Browse files
committed
[feature] Add API endpoint for indoor map coordinates #828
Implemented API to return device coordinates for a given location ID. Fixes #828
1 parent aa08611 commit 545dddb

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

openwisp_controller/geo/api/views.py

+39
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ class Meta(OrganizationManagedFilter.Meta):
5151
model = FloorPlan
5252

5353

54+
class DeviceFloorplanCoordinatesFilter(OrganizationManagedFilter):
55+
class Meta(OrganizationManagedFilter.Meta):
56+
model = Location
57+
fields = OrganizationManagedFilter.Meta.fields + ['floorplan__floor']
58+
59+
5460
class ListViewPagination(pagination.PageNumberPagination):
5561
page_size = 10
5662
page_size_query_param = 'page_size'
@@ -187,6 +193,38 @@ class GeoJsonLocationList(
187193
filterset_class = LocationOrganizationFilter
188194

189195

196+
class DeviceFloorplanCoordinatesList(ProtectedAPIMixin, generics.ListAPIView):
197+
"""
198+
List coordinates of device floorplan for a given location ID
199+
"""
200+
201+
serializer_class = DeviceLocationSerializer
202+
pagination_class = ListViewPagination
203+
filter_backends = [filters.DjangoFilterBackend]
204+
filterset_class = DeviceFloorplanCoordinatesFilter
205+
queryset = DeviceLocation.objects.select_related(
206+
"content_object", "location", "floorplan"
207+
)
208+
209+
def get_queryset(self):
210+
location_id = self.kwargs.get('pk')
211+
floor = self.request.query_params.get('floor')
212+
queryset = super().get_queryset().filter(location_id=location_id)
213+
if floor:
214+
queryset = queryset.filter(floorplan__floor=floor)
215+
return queryset
216+
217+
def list(self, request, *args, **kwargs):
218+
queryset = self.get_queryset()
219+
serializer = self.get_serializer(queryset, many=True)
220+
available_floors = queryset.values_list(
221+
'floorplan__floor', flat=True
222+
).distinct()
223+
return Response(
224+
{"devices": serializer.data, "available_floors": list(available_floors)}
225+
)
226+
227+
190228
class LocationDeviceList(
191229
FilterByParentManaged, ProtectedAPIMixin, generics.ListAPIView
192230
):
@@ -239,6 +277,7 @@ class LocationDetailView(
239277
# add with_geo filter to device API
240278
DeviceListCreateView.filterset_class = DeviceListFilter
241279

280+
device_floorplan_coordinates = DeviceFloorplanCoordinatesList.as_view()
242281
device_coordinates = DeviceCoordinatesView.as_view()
243282
device_location = DeviceLocationView.as_view()
244283
geojson = GeoJsonLocationList.as_view()

openwisp_controller/geo/tests/test_api.py

+27
Original file line numberDiff line numberDiff line change
@@ -1006,3 +1006,30 @@ def test_deactivated_device(self):
10061006
with self.subTest('Test deleting DeviceLocation'):
10071007
response = self.client.delete(url)
10081008
self.assertEqual(response.status_code, 403)
1009+
1010+
def test_floorplan_coordinates(self):
1011+
org = self._create_org()
1012+
location = self._create_location(type='indoor', organization=org)
1013+
floor1 = self._create_floorplan(floor=1, location=location)
1014+
floor2 = self._create_floorplan(floor=2, location=location)
1015+
device1 = self._create_device(
1016+
name='device1', mac_address='00:00:00:00:00:01', organization=org
1017+
)
1018+
device2 = self._create_device(
1019+
name='device2', mac_address='00:00:00:00:00:02', organization=org
1020+
)
1021+
self._create_object_location(
1022+
content_object=device1,
1023+
location=location,
1024+
floorplan=floor1,
1025+
organization=org,
1026+
)
1027+
self._create_object_location(
1028+
content_object=device2,
1029+
location=location,
1030+
floorplan=floor2,
1031+
organization=org,
1032+
)
1033+
path = reverse('geo_api:device_floorplan_coordinates', args=[location.id])
1034+
response = self.client.get(path)
1035+
print(response.__dict__)

openwisp_controller/geo/utils.py

+5
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,9 @@ def get_geo_urls(geo_views):
4141
geo_views.detail_location,
4242
name='detail_location',
4343
),
44+
path(
45+
'api/v1/controller/location/<str:pk>/floorplan/devices/',
46+
geo_views.device_floorplan_coordinates,
47+
name='device_floorplan_coordinates',
48+
),
4449
]

0 commit comments

Comments
 (0)