Skip to content

Commit c4523ea

Browse files
authored
Add proper pagination for API actions (#560)
Signed-off-by: Thomas Druez <[email protected]>
1 parent 6991566 commit c4523ea

File tree

4 files changed

+43
-13
lines changed

4 files changed

+43
-13
lines changed

CHANGELOG.rst

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ v31.1.0 (unreleased)
2121
the project details view, inside the run status tag.
2222
https://github.com/nexB/scancode.io/issues/300
2323

24+
- Add proper pagination for API actions: resources, packages, dependencies, and errors.
25+
2426
- Refine the fields ordering in API Serializers based on the toolkit order.
2527
https://github.com/nexB/scancode.io/issues/546
2628

scanpipe/api/views.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def resources(self, request, *args, **kwargs):
169169
paginated_qs = self.paginate_queryset(queryset)
170170
serializer = CodebaseResourceSerializer(paginated_qs, many=True)
171171

172-
return Response(serializer.data)
172+
return self.get_paginated_response(serializer.data)
173173

174174
@action(detail=True)
175175
def packages(self, request, *args, **kwargs):
@@ -179,7 +179,7 @@ def packages(self, request, *args, **kwargs):
179179
paginated_qs = self.paginate_queryset(queryset)
180180
serializer = DiscoveredPackageSerializer(paginated_qs, many=True)
181181

182-
return Response(serializer.data)
182+
return self.get_paginated_response(serializer.data)
183183

184184
@action(detail=True)
185185
def dependencies(self, request, *args, **kwargs):
@@ -189,7 +189,7 @@ def dependencies(self, request, *args, **kwargs):
189189
paginated_qs = self.paginate_queryset(queryset)
190190
serializer = DiscoveredDependencySerializer(paginated_qs, many=True)
191191

192-
return Response(serializer.data)
192+
return self.get_paginated_response(serializer.data)
193193

194194
@action(detail=True)
195195
def errors(self, request, *args, **kwargs):
@@ -199,7 +199,7 @@ def errors(self, request, *args, **kwargs):
199199
paginated_qs = self.paginate_queryset(queryset)
200200
serializer = ProjectErrorSerializer(paginated_qs, many=True)
201201

202-
return Response(serializer.data)
202+
return self.get_paginated_response(serializer.data)
203203

204204
@action(detail=True, methods=["get"])
205205
def file_content(self, request, *args, **kwargs):

scanpipe/models.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from django.core import checks
3939
from django.core.exceptions import ObjectDoesNotExist
4040
from django.core.serializers.json import DjangoJSONEncoder
41+
from django.core.validators import EMPTY_VALUES
4142
from django.db import models
4243
from django.db import transaction
4344
from django.db.models import Count
@@ -1163,12 +1164,12 @@ def update_from_data(self, data, override=False):
11631164
Update this object instance with the provided `data`.
11641165
The `save()` is called only if at least one field was modified.
11651166
"""
1166-
model_fields = self.__class__.model_fields()
1167+
model_fields = self.model_fields()
11671168
updated_fields = []
11681169

11691170
for field_name, value in data.items():
11701171
skip_reasons = [
1171-
not value,
1172+
value in EMPTY_VALUES,
11721173
field_name not in model_fields,
11731174
field_name in PURL_FIELDS,
11741175
]

scanpipe/tests/test_api.py

+34-7
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,12 @@ def test_scanpipe_api_project_action_resources(self):
330330
url = reverse("project-resources", args=[self.project1.uuid])
331331
response = self.csrf_client.get(url)
332332

333-
self.assertEqual(1, len(response.data))
334-
resource = response.data[0]
333+
self.assertEqual(1, response.data["count"])
334+
self.assertIsNone(response.data["next"])
335+
self.assertIsNone(response.data["previous"])
336+
self.assertEqual(1, len(response.data["results"]))
337+
338+
resource = response.data["results"][0]
335339
self.assertEqual(
336340
["pkg:deb/debian/[email protected]?uuid=610bed29-ce39-40e7-92d6-fd8b"],
337341
resource["for_packages"],
@@ -344,26 +348,49 @@ def test_scanpipe_api_project_action_resources(self):
344348
self.resource1.compliance_alert = CodebaseResource.Compliance.ERROR
345349
self.resource1.save()
346350
response = self.csrf_client.get(url)
347-
self.assertEqual("error", response.data[0]["compliance_alert"])
351+
self.assertEqual("error", response.data["results"][0]["compliance_alert"])
348352

349353
def test_scanpipe_api_project_action_packages(self):
350354
url = reverse("project-packages", args=[self.project1.uuid])
351355
response = self.csrf_client.get(url)
356+
self.assertEqual(1, response.data["count"])
357+
self.assertIsNone(response.data["next"])
358+
self.assertIsNone(response.data["previous"])
359+
self.assertEqual(1, len(response.data["results"]))
352360

353-
self.assertEqual(1, len(response.data))
354-
package = response.data[0]
361+
package = response.data["results"][0]
355362
self.assertEqual("pkg:deb/debian/[email protected]?arch=all", package["purl"])
356363
self.assertEqual("adduser", package["name"])
357364

365+
def test_scanpipe_api_project_action_dependencies(self):
366+
url = reverse("project-dependencies", args=[self.project1.uuid])
367+
response = self.csrf_client.get(url)
368+
self.assertEqual(1, response.data["count"])
369+
self.assertIsNone(response.data["next"])
370+
self.assertIsNone(response.data["previous"])
371+
self.assertEqual(1, len(response.data["results"]))
372+
373+
dependency = response.data["results"][0]
374+
self.assertEqual(dependency_data1["purl"], dependency["purl"])
375+
self.assertEqual(dependency_data1["scope"], dependency["scope"])
376+
self.assertEqual(dependency_data1["is_runtime"], dependency["is_runtime"])
377+
self.assertEqual(
378+
dependency_data1["dependency_uid"], dependency["dependency_uid"]
379+
)
380+
358381
def test_scanpipe_api_project_action_errors(self):
359382
url = reverse("project-errors", args=[self.project1.uuid])
360383
ProjectError.objects.create(
361384
project=self.project1, model="ModelName", details={}, message="Error"
362385
)
363386

364387
response = self.csrf_client.get(url)
365-
self.assertEqual(1, len(response.data))
366-
error = response.data[0]
388+
self.assertEqual(1, response.data["count"])
389+
self.assertIsNone(response.data["next"])
390+
self.assertIsNone(response.data["previous"])
391+
self.assertEqual(1, len(response.data["results"]))
392+
393+
error = response.data["results"][0]
367394
self.assertEqual("ModelName", error["model"])
368395
self.assertEqual({}, error["details"])
369396
self.assertEqual("Error", error["message"])

0 commit comments

Comments
 (0)