Skip to content

Commit

Permalink
feat: add parent_course query parameter to basic content-metadata end…
Browse files Browse the repository at this point in the history
…point

ENT-9840
  • Loading branch information
pwnage101 committed Jan 21, 2025
1 parent 7daab88 commit d86f5c1
Showing 1 changed file with 65 additions and 5 deletions.
70 changes: 65 additions & 5 deletions enterprise_catalog/apps/api/v1/views/content_metadata.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
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,
)
from rest_framework import permissions, viewsets
from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import action
from rest_framework.renderers import JSONRenderer
from rest_framework_xml.renderers import XMLRenderer

from enterprise_catalog.apps.api.v1.pagination import (
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 +51,72 @@ 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

def get_queryset(self, **kwargs):
"""
Returns all content metadata objects filtered by an optional request query param (LIST) ``content_identifiers``
"""
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.request.query_params.get('parent_course', False):
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 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)

# Coerce course runs to courses if requested.
if self.request.query_params.get('parent_course', False):
if not obj:
obj = get_object_or_404(self.queryset, id=pk)
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 d86f5c1

Please sign in to comment.