Skip to content

Commit

Permalink
[FC-0059] feat: Add order query param to lib v2 API (openedx#35005)
Browse files Browse the repository at this point in the history
* feat: Add `order` query param to lib v2 API

* test: Add tests for lib v2 `order` field
  • Loading branch information
yusuf-musleh authored Jul 2, 2024
1 parent 2717e5c commit c625a8d
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 2 deletions.
19 changes: 17 additions & 2 deletions openedx/core/djangoapps/content_libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand All @@ -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):
Expand Down
1 change: 1 addition & 0 deletions openedx/core/djangoapps/content_libraries/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
7 changes: 7 additions & 0 deletions openedx/core/djangoapps/content_libraries/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ def assertDictContainsEntries(self, big_dict, subset_dict):
"""
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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,27 @@ def test_library_filters(self):
'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):
Expand Down
9 changes: 9 additions & 0 deletions openedx/core/djangoapps/content_libraries/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -207,12 +214,14 @@ def get(self, request):
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)
Expand Down

0 comments on commit c625a8d

Please sign in to comment.