Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/release/RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
* [OSDEV-1158](https://opensupplyhub.atlassian.net/browse/OSDEV-1158) - The following features and improvements have been made:
1. Introduced a new POST `/api/v1/production-locations/` endpoint based on the API v1 specification. This endpoint allows the creation of a new moderation event for the production location creation with the given details.
2. Removed redundant redefinition of paths via the `as_view` method for all the v1 API endpoints since they are already defined via `DefaultRouter`.
* [OSDEV-1468](https://opensupplyhub.atlassian.net/browse/OSDEV-1468) - Limit the `page` parameter to `100` for the GET `/api/facilities/` endpoint. This will help prevent system downtimes, as larger pages (OFFSET) make it harder for the database to retrieve data, especially considering the large amount of data we have.

### Architecture/Environment changes
* [OSDEV-1170](https://opensupplyhub.atlassian.net/browse/OSDEV-1170) - Added the ability to automatically create a dump from the latest shared snapshot of the anonymized database from Production environment for use in the Test and Pre-Prod environments.
Expand Down
4 changes: 4 additions & 0 deletions src/django/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ class FacilitiesDownloadSettings:
DEFAULT_LIMIT = 10000


class FacilitiesListSettings:
DEFAULT_PAGE_LIMIT = 100


# API v1
class APIV1CommonErrorMessages:
COMMON_REQ_BODY_ERROR = 'The request body is invalid.'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from rest_framework.serializers import (
IntegerField,
Serializer
)

from api.constants import FacilitiesListSettings


class FacilityListPageParameterSerializer(Serializer):
'''
The serializer validates the page query parameter for the list action of
the FacilitiesViewSet.
'''
page = IntegerField(
required=False,
max_value=FacilitiesListSettings.DEFAULT_PAGE_LIMIT,
min_value=1,
error_messages={
'max_value': (
'This value must be less or equal to '
f'{FacilitiesListSettings.DEFAULT_PAGE_LIMIT}. If you need '
'access to more data, please contact '
'[email protected].'),
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import json

from rest_framework.test import APITestCase
from django.urls import reverse


class TestPageLimitInFacilitiesViewsetListAction(APITestCase):
def setUp(self):
self.url = reverse('facility-list')

def test_page_limit_blocks_request_when_exceeding_limit(self):
expected_response = {
'page': [
('This value must be less or equal to 100. If you need access '
'to more data, please contact [email protected].')
]
}

page = {'page': 101}

response = self.client.get(self.url, page)
self.assertEqual(response.status_code, 400)

response_body_dict = json.loads(response.content)
self.assertEqual(response_body_dict, expected_response)

def test_page_limit_does_not_block_request_within_limit(self):
page = {'page': 1}

response = self.client.get(self.url, page)
response_body_dict = json.loads(response.content)

# Made sure that the successful response with an empty facility list
# is returned even if the test database is empty.
self.assertEqual(response.status_code, 200)
self.assertEqual(response_body_dict['count'], 0)
8 changes: 8 additions & 0 deletions src/django/api/views/facility/facilities_view_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@
FacilityQueryParamsSerializer,
FacilityUpdateLocationParamsSerializer,
)
from api.serializers.facility.facility_list_page_parameter_serializer \
import FacilityListPageParameterSerializer
from ...throttles import DataUploadThrottle

from ..disabled_pagination_inspector import DisabledPaginationInspector
Expand Down Expand Up @@ -220,6 +222,12 @@ def list(self, request):
]
}
"""
page_serializer = FacilityListPageParameterSerializer(
data=request.query_params
)
if not page_serializer.is_valid():
raise ValidationError(page_serializer.errors)

params = FacilityQueryParamsSerializer(data=request.query_params)

if not params.is_valid():
Expand Down
13 changes: 13 additions & 0 deletions src/django/api/views/facility/facility_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
TYPE_INTEGER
)

from api.constants import FacilitiesListSettings

facility_parameters = [
Parameter(
'created_at_of_data_points',
Expand All @@ -31,6 +33,17 @@
]

facilities_list_parameters = [
Parameter(
'page',
IN_QUERY,
type=TYPE_INTEGER,
required=False,
description=(
'A page number within the paginated result set. As of now, the '
'last page that can be accessed is '
f'{FacilitiesListSettings.DEFAULT_PAGE_LIMIT}. To access more '
'data, please contact [email protected].'),
),
Parameter(
'q',
IN_QUERY,
Expand Down