Commit 3a178f57 by Michael Frey Committed by Michael Frey

Add the ability to access and filter courses by UUID and not just key.

LEARNER-2882
parent 70a95fcf
......@@ -128,10 +128,11 @@ class FilterSetMixin:
class CourseFilter(filters.FilterSet):
keys = CharListFilter(name='key', lookup_expr='in')
uuids = UUIDListFilter()
class Meta:
model = Course
fields = ['keys']
fields = ('keys', 'uuids',)
class CourseRunFilter(FilterSetMixin, filters.FilterSet):
......
......@@ -37,6 +37,15 @@ class CourseViewSetTests(SerializationMixin, APITestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data, self.serialize_course(self.course))
def test_get_uuid(self):
""" Verify the endpoint returns the details for a single course with UUID. """
url = reverse('api:v1:course-detail', kwargs={'key': self.course.uuid})
with self.assertNumQueries(21):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data, self.serialize_course(self.course))
def test_get_exclude_deleted_programs(self):
""" Verify the endpoint returns no deleted associated programs """
ProgramFactory(courses=[self.course], status=ProgramStatus.Deleted)
......@@ -221,6 +230,17 @@ class CourseViewSetTests(SerializationMixin, APITestCase):
response = self.client.get(url)
self.assertListEqual(response.data['results'], self.serialize_course(courses, many=True))
def test_list_uuid_filter(self):
""" Verify the endpoint returns a list of courses filtered by the specified uuid. """
courses = CourseFactory.create_batch(3, partner=self.partner)
courses = sorted(courses, key=lambda course: course.key.lower())
uuids = ','.join([str(course.uuid) for course in courses])
url = '{root}?uuids={uuids}'.format(root=reverse('api:v1:course-list'), uuids=uuids)
with self.assertNumQueries(40):
response = self.client.get(url)
self.assertListEqual(response.data['results'], self.serialize_course(courses, many=True))
def test_list_exclude_utm(self):
""" Verify the endpoint returns marketing URLs without UTM parameters. """
url = reverse('api:v1:course-list') + '?exclude_utm=1'
......
import re
from django.db.models.functions import Lower
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
......@@ -7,7 +10,7 @@ from course_discovery.apps.api import filters, serializers
from course_discovery.apps.api.pagination import ProxiedPagination
from course_discovery.apps.api.utils import get_query_param
from course_discovery.apps.course_metadata.choices import CourseRunStatus
from course_discovery.apps.course_metadata.constants import COURSE_ID_REGEX
from course_discovery.apps.course_metadata.constants import COURSE_ID_REGEX, COURSE_UUID_REGEX
from course_discovery.apps.course_metadata.models import Course, CourseRun
......@@ -17,14 +20,35 @@ class CourseViewSet(viewsets.ReadOnlyModelViewSet):
filter_backends = (DjangoFilterBackend,)
filter_class = filters.CourseFilter
lookup_field = 'key'
lookup_value_regex = COURSE_ID_REGEX
lookup_value_regex = COURSE_ID_REGEX + '|' + COURSE_UUID_REGEX
permission_classes = (IsAuthenticated,)
serializer_class = serializers.CourseWithProgramsSerializer
course_key_regex = re.compile(COURSE_ID_REGEX)
course_uuid_regex = re.compile(COURSE_UUID_REGEX)
# Explicitly support PageNumberPagination and LimitOffsetPagination. Future
# versions of this API should only support the system default, PageNumberPagination.
pagination_class = ProxiedPagination
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
key = self.kwargs['key']
if self.course_key_regex.match(key):
filter_key = 'key'
elif self.course_uuid_regex.match(key):
filter_key = 'uuid'
filter_kwargs = {filter_key: key}
obj = get_object_or_404(queryset, **filter_kwargs)
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj
def get_queryset(self):
partner = self.request.site.partner
q = self.request.query_params.get('q')
......
COURSE_ID_REGEX = r'[^/+]+(/|\+)[^/+]+'
COURSE_RUN_ID_REGEX = r'[^/+]+(/|\+)[^/+]+(/|\+)[^/]+'
COURSE_UUID_REGEX = r'[0-9a-f-]+'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment