Skip to content

Commit 9056568

Browse files
authored
Fix/node list access (#140)
* chore: update NodesViews list_nodes action(GET) to allow non-authenticated requests to access nodes, optimize list_nodes func * chore: optimize last_active_nodes fetch to last one_hour * chore: filter last active nodes to 1 year
1 parent 607b559 commit 9056568

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

sensorsafrica/api/v2/views.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from django.conf import settings
1010
from django.utils import timezone
1111
from django.db import connection
12-
from django.db.models import ExpressionWrapper, F, FloatField, Max, Min, Sum, Avg, Q, Count
12+
from django.db.models import ExpressionWrapper, F, FloatField, Max, Min, Sum, Avg, Q, Count, Prefetch
1313
from django.db.models.functions import Cast, TruncHour, TruncDay, TruncMonth
1414
from django.utils.decorators import method_decorator
1515
from django.utils.text import slugify
@@ -134,31 +134,44 @@ class NodesView(viewsets.ViewSet):
134134
authentication_classes = [SessionAuthentication, TokenAuthentication]
135135
permission_classes = [IsAuthenticated]
136136

137-
@action(detail=False, methods=["get"], url_path="list-nodes", url_name="list_nodes")
137+
# Note: Allow access to list_nodes for https://v2.map.aq.sensors.africa/#4/-4.46/19.54
138+
@action(detail=False, methods=["get"], url_path="list-nodes", url_name="list_nodes", permission_classes=[AllowAny])
138139
def list_nodes(self, request):
139140
"""List all public nodes with active sensors."""
141+
now = datetime.datetime.now()
142+
one_year_ago = now - datetime.timedelta(days=365)
143+
144+
last_active_nodes = (
145+
LastActiveNodes.objects.filter(last_data_received_at__gte=one_year_ago)
146+
.select_related("node", "location")
147+
.prefetch_related(
148+
Prefetch(
149+
"node__sensors",
150+
queryset=Sensor.objects.filter(public=True),
151+
)
152+
)
153+
)
154+
140155
nodes = []
156+
141157
# Loop through the last active nodes
142-
for last_active in LastActiveNodes.objects.iterator():
158+
for last_active in last_active_nodes:
143159
# Get the current node only if it has public sensors
144-
node = Node.objects.filter(
145-
Q(id=last_active.node.id), Q(sensors__public=True)
146-
).first()
147-
if node is None:
160+
node = last_active.node
161+
if not node.sensors.exists():
148162
continue
149163

150164
# The last acive date
151165
last_data_received_at = last_active.last_data_received_at
152166

153167
# last_data_received_at
154168
stats = []
155-
moved_to = None
156169
# Get data stats from 5mins before last_data_received_at
157170
if last_data_received_at:
158171
last_5_mins = last_data_received_at - datetime.timedelta(minutes=5)
159172
stats = (
160173
SensorDataValue.objects.filter(
161-
Q(sensordata__sensor__node=last_active.node.id),
174+
Q(sensordata__sensor__node=node.id),
162175
# Open endpoints should return data from public sensors
163176
# only in case a node has both public & private sensors
164177
Q(sensordata__sensor__public=True),
@@ -170,7 +183,6 @@ def list_nodes(self, request):
170183
# Match only valid float text
171184
Q(value__regex=r"^\-?\d+(\.?\d+)?$"),
172185
)
173-
.order_by()
174186
.values("value_type")
175187
.annotate(
176188
sensor_id=F("sensordata__sensor__id"),
@@ -184,6 +196,7 @@ def list_nodes(self, request):
184196

185197
# If the last_active node location is not same as current node location
186198
# then the node has moved locations since it was last active
199+
moved_to = None
187200
if last_active.location.id != node.location.id:
188201
moved_to = {
189202
"name": node.location.location,

0 commit comments

Comments
 (0)