[FC-0059] feat: Add order query param to lib v2 API (#35005)
* feat: Add `order` query param to lib v2 API * test: Add tests for lib v2 `order` field
This commit is contained in:
@@ -242,7 +242,7 @@ class LibraryXBlockType:
|
||||
# ============
|
||||
|
||||
|
||||
def get_libraries_for_user(user, org=None, library_type=None, text_search=None):
|
||||
def get_libraries_for_user(user, org=None, library_type=None, text_search=None, order=None):
|
||||
"""
|
||||
Return content libraries that the user has permission to view.
|
||||
"""
|
||||
@@ -263,7 +263,22 @@ def get_libraries_for_user(user, org=None, library_type=None, text_search=None):
|
||||
Q(learning_package__description__icontains=text_search)
|
||||
)
|
||||
|
||||
return permissions.perms[permissions.CAN_VIEW_THIS_CONTENT_LIBRARY].filter(user, qs)
|
||||
filtered = permissions.perms[permissions.CAN_VIEW_THIS_CONTENT_LIBRARY].filter(user, qs)
|
||||
|
||||
if order:
|
||||
order_query = 'learning_package__'
|
||||
valid_order_fields = ['title', 'created', 'updated']
|
||||
# If order starts with a -, that means order descending (default is ascending)
|
||||
if order.startswith('-'):
|
||||
order_query = f"-{order_query}"
|
||||
order = order[1:]
|
||||
|
||||
if order in valid_order_fields:
|
||||
return filtered.order_by(f"{order_query}{order}")
|
||||
else:
|
||||
log.exception(f"Error ordering libraries by {order}: Invalid order field")
|
||||
|
||||
return filtered
|
||||
|
||||
|
||||
def get_metadata(queryset, text_search=None):
|
||||
|
||||
@@ -115,6 +115,7 @@ class BaseFilterSerializer(serializers.Serializer):
|
||||
"""
|
||||
text_search = serializers.CharField(default=None, required=False)
|
||||
org = serializers.CharField(default=None, required=False)
|
||||
order = serializers.CharField(default=None, required=False)
|
||||
|
||||
|
||||
class ContentLibraryFilterSerializer(BaseFilterSerializer):
|
||||
|
||||
@@ -89,6 +89,13 @@ class ContentLibrariesRestApiTest(APITransactionTestCase):
|
||||
"""
|
||||
assert big_dict.items() >= subset_dict.items()
|
||||
|
||||
def assertOrderEqual(self, libraries_list, expected_order):
|
||||
"""
|
||||
Assert that the provided list of libraries match the order of expected
|
||||
list by comparing the slugs.
|
||||
"""
|
||||
assert [lib["slug"] for lib in libraries_list] == expected_order
|
||||
|
||||
# API helpers
|
||||
|
||||
def _api(self, method, url, data, expect_response):
|
||||
|
||||
@@ -230,6 +230,27 @@ class ContentLibrariesTestCase(ContentLibrariesRestApiTest, OpenEdxEventsTestMix
|
||||
'text_search': 'library-title-4'})) == 1
|
||||
assert len(self._list_libraries({'type': VIDEO})) == 3
|
||||
|
||||
self.assertOrderEqual(
|
||||
self._list_libraries({'order': 'title'}),
|
||||
["test-lib-filter-1", "test-lib-filter-2", "l3", "l4", "l5"],
|
||||
)
|
||||
self.assertOrderEqual(
|
||||
self._list_libraries({'order': '-title'}),
|
||||
["l5", "l4", "l3", "test-lib-filter-2", "test-lib-filter-1"],
|
||||
)
|
||||
self.assertOrderEqual(
|
||||
self._list_libraries({'order': 'created'}),
|
||||
["test-lib-filter-1", "test-lib-filter-2", "l3", "l4", "l5"],
|
||||
)
|
||||
self.assertOrderEqual(
|
||||
self._list_libraries({'order': '-created'}),
|
||||
["l5", "l4", "l3", "test-lib-filter-2", "test-lib-filter-1"],
|
||||
)
|
||||
# An invalid order doesn't apply any specific ordering to the result, so just
|
||||
# check if successfully returned libraries
|
||||
assert len(self._list_libraries({'order': 'invalid'})) == 5
|
||||
assert len(self._list_libraries({'order': '-invalid'})) == 5
|
||||
|
||||
# General Content Library XBlock tests:
|
||||
|
||||
def test_library_blocks(self):
|
||||
|
||||
@@ -196,6 +196,13 @@ class LibraryRootView(GenericAPIView):
|
||||
str,
|
||||
description="The string used to filter libraries by searching in title, id, org, or description",
|
||||
),
|
||||
apidocs.query_parameter(
|
||||
'order',
|
||||
str,
|
||||
description=(
|
||||
"Name of the content library field to sort the results by. Prefix with a '-' to sort descending."
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def get(self, request):
|
||||
@@ -207,12 +214,14 @@ class LibraryRootView(GenericAPIView):
|
||||
org = serializer.validated_data['org']
|
||||
library_type = serializer.validated_data['type']
|
||||
text_search = serializer.validated_data['text_search']
|
||||
order = serializer.validated_data['order']
|
||||
|
||||
queryset = api.get_libraries_for_user(
|
||||
request.user,
|
||||
org=org,
|
||||
library_type=library_type,
|
||||
text_search=text_search,
|
||||
order=order,
|
||||
)
|
||||
paginated_qs = self.paginate_queryset(queryset)
|
||||
result = api.get_metadata(paginated_qs)
|
||||
|
||||
Reference in New Issue
Block a user