Skip to content

Commit

Permalink
add rest api pagination (#1994)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed Sep 11, 2024
1 parent 185955a commit 0875cd4
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 100 deletions.
3 changes: 3 additions & 0 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@
'knox.auth.TokenAuthentication',
),
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
'DEFAULT_PAGINATION_CLASS': (
'rest_framework.pagination.PageNumberPagination'
),
'PAGE_SIZE': env.int('SODAR_API_PAGE_SIZE', 100),
}

Expand Down
177 changes: 90 additions & 87 deletions landingzones/tests/test_views_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def setUp(self):
self.study = self.investigation.studies.first()
self.assay = self.study.assays.first()
# Create LandingZone
self.landing_zone = self.make_landing_zone(
self.zone = self.make_landing_zone(
title=ZONE_TITLE,
project=self.project,
user=self.user,
Expand All @@ -74,50 +74,79 @@ def setUp(self):
class TestLandingZoneListAPIView(TestLandingZoneAPIViewsBase):
"""Tests for LandingZoneListAPIView"""

def test_get_owner(self):
"""Test LandingZoneListAPIView get() as project owner"""
irods_backend = get_backend_api('omics_irods')
url = reverse(
def setUp(self):
super().setUp()
self.irods_backend = get_backend_api('omics_irods')
self.url = reverse(
'landingzones:api_list', kwargs={'project': self.project.sodar_uuid}
)

response = self.request_knox(url)
def test_get_owner(self):
"""Test LandingZoneListAPIView GET as project owner"""
response = self.request_knox(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)

expected = {
'title': self.landing_zone.title,
'title': self.zone.title,
'project': str(self.project.sodar_uuid),
'user': self.get_serialized_user(self.user),
'assay': str(self.assay.sodar_uuid),
'status': self.landing_zone.status,
'status_info': self.landing_zone.status_info,
'status': self.zone.status,
'status_info': self.zone.status_info,
'status_locked': False,
'date_modified': self.get_drf_datetime(
self.landing_zone.date_modified
),
'description': self.landing_zone.description,
'user_message': self.landing_zone.user_message,
'configuration': self.landing_zone.configuration,
'config_data': self.landing_zone.config_data,
'irods_path': irods_backend.get_path(self.landing_zone),
'sodar_uuid': str(self.landing_zone.sodar_uuid),
'date_modified': self.get_drf_datetime(self.zone.date_modified),
'description': self.zone.description,
'user_message': self.zone.user_message,
'configuration': self.zone.configuration,
'config_data': self.zone.config_data,
'irods_path': self.irods_backend.get_path(self.zone),
'sodar_uuid': str(self.zone.sodar_uuid),
}
self.assertEqual(json.loads(response.content)[0], expected)

def test_get_pagination(self):
"""Test GET with pagination"""
url = self.url + '?page=1'
response = self.request_knox(url)
self.assertEqual(response.status_code, 200)
expected = {
'count': 1,
'next': None,
'previous': None,
'results': [
{
'title': self.zone.title,
'project': str(self.project.sodar_uuid),
'user': self.get_serialized_user(self.user),
'assay': str(self.assay.sodar_uuid),
'status': self.zone.status,
'status_info': self.zone.status_info,
'status_locked': False,
'date_modified': self.get_drf_datetime(
self.zone.date_modified
),
'description': self.zone.description,
'user_message': self.zone.user_message,
'configuration': self.zone.configuration,
'config_data': self.zone.config_data,
'irods_path': self.irods_backend.get_path(self.zone),
'sodar_uuid': str(self.zone.sodar_uuid),
}
],
}
self.assertEqual(json.loads(response.content), expected)

def test_get_no_own_zones(self):
"""Test LandingZoneListAPIView get() as user with no own zones"""
url = reverse(
'landingzones:api_list', kwargs={'project': self.project.sodar_uuid}
)
"""Test GET as user with no own zones"""
response = self.request_knox(
url, token=self.get_token(self.user_contributor)
self.url, token=self.get_token(self.user_contributor)
)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)

def test_get_finished_default(self):
"""Test get() with finished zone and no finished parameter"""
"""Test GET with finished zone and no finished parameter"""
self.make_landing_zone(
title=ZONE_TITLE + '_moved',
project=self.project,
Expand All @@ -126,19 +155,16 @@ def test_get_finished_default(self):
description=ZONE_DESC,
status=ZONE_STATUS_MOVED,
)
url = reverse(
'landingzones:api_list', kwargs={'project': self.project.sodar_uuid}
)
response = self.request_knox(url)
response = self.request_knox(self.url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
self.assertEqual(
json.loads(response.content)[0]['sodar_uuid'],
str(self.landing_zone.sodar_uuid),
str(self.zone.sodar_uuid),
)

def test_get_finished_false(self):
"""Test get() with finished zone and finished=0"""
"""Test GET with finished zone and finished=0"""
self.make_landing_zone(
title=ZONE_TITLE + '_moved',
project=self.project,
Expand All @@ -147,23 +173,17 @@ def test_get_finished_false(self):
description=ZONE_DESC,
status=ZONE_STATUS_MOVED,
)
url = (
reverse(
'landingzones:api_list',
kwargs={'project': self.project.sodar_uuid},
)
+ '?finished=0'
)
url = self.url + '?finished=0'
response = self.request_knox(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
self.assertEqual(
json.loads(response.content)[0]['sodar_uuid'],
str(self.landing_zone.sodar_uuid),
str(self.zone.sodar_uuid),
)

def test_get_finished_true(self):
"""Test get() with finished zone and finished=1"""
"""Test GET with finished zone and finished=1"""
self.make_landing_zone(
title=ZONE_TITLE + '_moved',
project=self.project,
Expand All @@ -172,13 +192,7 @@ def test_get_finished_true(self):
description=ZONE_DESC,
status=ZONE_STATUS_MOVED,
)
url = (
reverse(
'landingzones:api_list',
kwargs={'project': self.project.sodar_uuid},
)
+ '?finished=1'
)
url = self.url + '?finished=1'
response = self.request_knox(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
Expand All @@ -188,42 +202,40 @@ class TestLandingZoneRetrieveAPIView(TestLandingZoneAPIViewsBase):
"""Tests for LandingZoneRetrieveAPIView"""

def test_get(self):
"""Test LandingZoneRetrieveAPIView get() as zone owner"""
"""Test LandingZoneRetrieveAPIView GET as zone owner"""
irods_backend = get_backend_api('omics_irods')
url = reverse(
'landingzones:api_retrieve',
kwargs={'landingzone': self.landing_zone.sodar_uuid},
kwargs={'landingzone': self.zone.sodar_uuid},
)
response = self.request_knox(url)
self.assertEqual(response.status_code, 200)

expected = {
'title': self.landing_zone.title,
'title': self.zone.title,
'project': str(self.project.sodar_uuid),
'user': self.get_serialized_user(self.user),
'assay': str(self.assay.sodar_uuid),
'status': self.landing_zone.status,
'status_info': self.landing_zone.status_info,
'status': self.zone.status,
'status_info': self.zone.status_info,
'status_locked': False,
'date_modified': self.get_drf_datetime(
self.landing_zone.date_modified
),
'description': self.landing_zone.description,
'user_message': self.landing_zone.user_message,
'configuration': self.landing_zone.configuration,
'config_data': self.landing_zone.config_data,
'irods_path': irods_backend.get_path(self.landing_zone),
'sodar_uuid': str(self.landing_zone.sodar_uuid),
'date_modified': self.get_drf_datetime(self.zone.date_modified),
'description': self.zone.description,
'user_message': self.zone.user_message,
'configuration': self.zone.configuration,
'config_data': self.zone.config_data,
'irods_path': irods_backend.get_path(self.zone),
'sodar_uuid': str(self.zone.sodar_uuid),
}
self.assertEqual(json.loads(response.content), expected)

def test_get_locked(self):
"""Test get() with locked landing zone status"""
self.landing_zone.status = ZONE_STATUS_MOVING
self.landing_zone.save()
"""Test GET with locked landing zone status"""
self.zone.status = ZONE_STATUS_MOVING
self.zone.save()
url = reverse(
'landingzones:api_retrieve',
kwargs={'landingzone': self.landing_zone.sodar_uuid},
kwargs={'landingzone': self.zone.sodar_uuid},
)
response = self.request_knox(url)
self.assertEqual(response.status_code, 200)
Expand All @@ -233,17 +245,20 @@ def test_get_locked(self):
class TestLandingZoneUpdateAPIView(TestLandingZoneAPIViewsBase):
"""Tests for LandingZoneUpdateAPIView"""

def test_patch(self):
"""Test LandingZoneUpdateAPIView patch() as zone owner"""
url = reverse(
def setUp(self):
super().setUp()
self.url = reverse(
'landingzones:api_update',
kwargs={'landingzone': self.landing_zone.sodar_uuid},
kwargs={'landingzone': self.zone.sodar_uuid},
)

def test_patch(self):
"""Test LandingZoneUpdateAPIView PATCH as zone owner"""
data = {
'description': 'New description',
'user_message': 'New user message',
}
response = self.request_knox(url, method='PATCH', data=data)
response = self.request_knox(self.url, method='PATCH', data=data)
self.assertEqual(response.status_code, 200)
self.assertEqual(
json.loads(response.content)['description'], 'New description'
Expand All @@ -253,26 +268,18 @@ def test_patch(self):
)

def test_patch_title(self):
"""Test updating title with patch() (should fail)"""
url = reverse(
'landingzones:api_update',
kwargs={'landingzone': self.landing_zone.sodar_uuid},
)
"""Test PATCH to update title (should fail)"""
data = {'title': 'New title'}
response = self.request_knox(url, method='PATCH', data=data)
response = self.request_knox(self.url, method='PATCH', data=data)
self.assertEqual(response.status_code, 400)

def test_put(self):
"""Test LandingZoneUpdateAPIView put() as zone owner"""
url = reverse(
'landingzones:api_update',
kwargs={'landingzone': self.landing_zone.sodar_uuid},
)
"""Test PUT as zone owner"""
data = {
'description': 'New description',
'user_message': 'New user message',
}
response = self.request_knox(url, method='PUT', data=data)
response = self.request_knox(self.url, method='PUT', data=data)
self.assertEqual(response.status_code, 200)
self.assertEqual(
json.loads(response.content)['description'], 'New description'
Expand All @@ -282,11 +289,7 @@ def test_put(self):
)

def test_put_title(self):
"""Test updating title with put() (should fail)"""
url = reverse(
'landingzones:api_update',
kwargs={'landingzone': self.landing_zone.sodar_uuid},
)
"""Test PUT to update title (should fail)"""
data = {'title': 'New title'}
response = self.request_knox(url, method='PUT', data=data)
response = self.request_knox(self.url, method='PUT', data=data)
self.assertEqual(response.status_code, 400)
7 changes: 7 additions & 0 deletions landingzones/views_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from projectroles.views_api import (
SODARAPIBaseProjectMixin,
SODARAPIGenericProjectMixin,
SODARPageNumberPagination,
)

# Samplesheets dependency
Expand Down Expand Up @@ -119,17 +120,23 @@ class ZoneListAPIView(
finished (meaning moved or deleted) zones if the "finished" parameter is
set.
Supports optional pagination for listing by providing the ``page`` query
string. This will return results in the Django Rest Framework
``PageNumberPagination`` format.
**URL:** ``/landingzones/api/list/{Project.sodar_uuid}?finished={integer}``
**Methods:** ``GET``
**Parameters:**
- ``finished``: Include finished zones if 1 (integer)
- ``page``: Page number for paginated results (int, optional)
**Returns:** List of landing zone details (see ``ZoneRetrieveAPIView``)
"""

pagination_class = SODARPageNumberPagination
permission_required = 'landingzones.view_zone_own'
serializer_class = LandingZoneSerializer

Expand Down
Loading

0 comments on commit 0875cd4

Please sign in to comment.