Skip to content

Commit

Permalink
feat: add coerce_to_parent_course query param to basic content-metada…
Browse files Browse the repository at this point in the history
…ta endpoint

ENT-9840
  • Loading branch information
pwnage101 committed Jan 21, 2025
1 parent 7daab88 commit b61c41d
Showing 1 changed file with 72 additions and 5 deletions.
77 changes: 72 additions & 5 deletions enterprise_catalog/apps/api/v1/views/content_metadata.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import uuid

from django.db.models import Q
from django.shortcuts import get_object_or_404
from edx_rest_framework_extensions.auth.jwt.authentication import (
JwtAuthentication,
)
Expand All @@ -12,6 +14,7 @@
PageNumberWithSizePagination,
)
from enterprise_catalog.apps.api.v1.serializers import ContentMetadataSerializer
from enterprise_catalog.apps.catalog.constants import COURSE_RUN
from enterprise_catalog.apps.catalog.models import ContentMetadata


Expand Down Expand Up @@ -47,16 +50,80 @@ class ContentMetadataView(viewsets.ReadOnlyModelViewSet):
queryset = ContentMetadata.objects.all()
pagination_class = PageNumberWithSizePagination

@property
def pk_is_object_id(self):
return self.kwargs.get('pk', '').isdigit()

@property
def pk_is_content_uuid(self):
return not self.pk_is_object_id and is_valid_uuid(self.kwargs.get('pk'))

@property
def pk_is_content_key(self):
return not self.pk_is_object_id and not self.pk_is_content_uuid

@property
def coerce_to_parent_course(self):
return self.request.query_params.get('coerce_to_parent_course', False)

def get_queryset(self, **kwargs):
"""
Returns all content metadata objects filtered by an optional request query param (LIST) ``content_identifiers``
If ``?coerce_to_parent_course=true` is passed to the list endpoint, any course runs which
would have been returned are coerced into their parent course in the response. No course
runs are returned when this setting is true.
"""
content_filters = self.request.query_params.getlist('content_identifiers')
queryset = self.queryset

# Find all directly requested content
content_filters = self.request.query_params.getlist('content_identifiers')
queryset_direct = None
if content_filters:
content_uuids, content_keys = partition(is_valid_uuid, content_filters)
if content_keys:
queryset = queryset.filter(content_key__in=content_filters)
if content_uuids:
queryset = queryset.filter(content_uuid__in=content_filters)
queryset_direct = self.queryset.filter(
Q(content_uuid__in=content_uuids) | Q(content_key__in=content_keys)
)
queryset = queryset_direct

# If ``?parent_course=true`` was passed, exclude course runs.
if self.coerce_to_parent_course:
query_filters = ~Q(content_type=COURSE_RUN)
# If ``?content_identifiers=`` was passed, follow any matched course run objects back up
# to their parent courses and include those in the response.
if content_filters:
parent_content_keys = (
record[0] for record in
queryset_direct.filter(content_type=COURSE_RUN).values_list('parent_content_key')
)
all_content_keys_to_find = content_keys+parent_content_keys
query_filters &= (
Q(content_uuid__in=content_uuids) | Q(content_key__in=all_content_keys_to_find)
)
queryset = self.queryset.filter(query_filters)

return queryset

def retrieve(self, request, *args, pk=None, **kwargs):
"""
Override to support querying by content key/uuid, and to optionally coerce runs to courses.
"""
# Support alternative pk types besisdes just the raw object IDs (which are completely opaque
# to API clients).
obj = None
if self.pk_is_content_uuid:
obj = get_object_or_404(self.queryset, content_uuid=pk)
if self.pk_is_content_key:
obj = get_object_or_404(self.queryset, content_key=pk)
else:
obj = get_object_or_404(self.queryset, pk=pk)

# Coerce course runs to courses if requested.
if self.coerce_to_parent_course:
if obj.content_type == COURSE_RUN:
obj = get_object_or_404(self.queryset, content_key=obj.parent_content_key)

# Finally, call super's retrieve() which has more DRF guts that are best not duplicated in
# this codebase.
pk_to_retrieve = obj.id if obj else pk
return super().retrieve(request, *args, pk=pk_to_retrieve, **kwargs)

0 comments on commit b61c41d

Please sign in to comment.