From 6193d0abbf7f490ccff3abc918a6fc4e335f945d Mon Sep 17 00:00:00 2001 From: zubair-arbi Date: Wed, 8 Mar 2017 16:32:52 +0500 Subject: [PATCH] add support for course run key in catalog contains endpoint ENT-201 --- .../api/v1/tests/test_views/test_catalogs.py | 42 ++++++++++++++----- .../apps/api/v1/views/catalogs.py | 17 +++++++- course_discovery/apps/catalogs/models.py | 19 ++++++++- .../apps/catalogs/tests/test_models.py | 11 ++++- 4 files changed, 74 insertions(+), 15 deletions(-) diff --git a/course_discovery/apps/api/v1/tests/test_views/test_catalogs.py b/course_discovery/apps/api/v1/tests/test_views/test_catalogs.py index d9b6e1950f..b77d098b25 100644 --- a/course_discovery/apps/api/v1/tests/test_views/test_catalogs.py +++ b/course_discovery/apps/api/v1/tests/test_views/test_catalogs.py @@ -59,6 +59,20 @@ def assert_catalog_created(self, **headers): self.assertEqual(catalog.query, query) self.assertListEqual(list(catalog.viewers), [viewer]) + def assert_catalog_contains_query_string(self, query_string_kwargs, course_key): + """ + Helper method to validate the provided course key or course run key + in the catalog contains endpoint. + """ + query_string = urllib.parse.urlencode(query_string_kwargs) + url = '{base_url}?{query_string}'.format( + base_url=reverse('api:v1:catalog-contains', kwargs={'id': self.catalog.id}), + query_string=query_string + ) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data, {'courses': {course_key: True}}) + def grant_catalog_permission_to_user(self, user, action, catalog=None): """ Grant the user access to view `self.catalog`. """ catalog = catalog or self.catalog @@ -152,18 +166,24 @@ def test_courses(self): assert response.status_code == 200 assert response.data['results'] == self.serialize_catalog_course(courses, many=True) - def test_contains(self): - """ Verify the endpoint returns a filtered list of courses contained in the catalog. """ + def test_contains_for_course_key(self): + """ + Verify the endpoint returns a filtered list of courses contained in + the catalog for course keys with the format "org+course". + """ course_key = self.course.key - query_string = urllib.parse.urlencode({'course_id': course_key}) - url = '{base_url}?{query_string}'.format( - base_url=reverse('api:v1:catalog-contains', kwargs={'id': self.catalog.id}), - query_string=query_string - ) - - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.data, {'courses': {course_key: True}}) + query_string_kwargs = {'course_id': course_key} + self.assert_catalog_contains_query_string(query_string_kwargs, course_key) + + def test_contains_for_course_run_key(self): + """ + Verify the endpoint returns a filtered list of courses contained in + the catalog for course run keys with the format "org/course/run" or + "course-v1:org+course+key". + """ + course_run_key = self.course_run.key + query_string_kwargs = {'course_run_id': course_run_key} + self.assert_catalog_contains_query_string(query_string_kwargs, course_run_key) def test_csv(self): SeatFactory(type='audit', course_run=self.course_run) diff --git a/course_discovery/apps/api/v1/views/catalogs.py b/course_discovery/apps/api/v1/views/catalogs.py index 3ce22724d6..4cdcaea37b 100644 --- a/course_discovery/apps/api/v1/views/catalogs.py +++ b/course_discovery/apps/api/v1/views/catalogs.py @@ -113,12 +113,25 @@ def contains(self, request, id=None): # pylint: disable=redefined-builtin,unuse type: string paramType: query multiple: true + - name: course_run_id + description: Course run IDs to check for existence in the Catalog. + required: false + type: string + paramType: query + multiple: true """ course_ids = request.query_params.get('course_id') - course_ids = course_ids.split(',') + course_run_ids = request.query_params.get('course_run_id') catalog = self.get_object() - courses = catalog.contains(course_ids) + courses = {} + if course_ids: + course_ids = course_ids.split(',') + courses.update(catalog.contains(course_ids)) + + if course_run_ids: + course_run_ids = course_run_ids.split(',') + courses.update(catalog.contains_course_runs(course_run_ids)) instance = {'courses': courses} serializer = serializers.ContainedCoursesSerializer(instance) diff --git a/course_discovery/apps/catalogs/models.py b/course_discovery/apps/catalogs/models.py index 5b29dbe0fa..195897862b 100644 --- a/course_discovery/apps/catalogs/models.py +++ b/course_discovery/apps/catalogs/models.py @@ -7,7 +7,7 @@ from haystack.query import SearchQuerySet from course_discovery.apps.core.mixins import ModelPermissionsMixin -from course_discovery.apps.course_metadata.models import Course +from course_discovery.apps.course_metadata.models import Course, CourseRun class Catalog(ModelPermissionsMixin, TimeStampedModel): @@ -56,6 +56,23 @@ def contains(self, course_ids): # pylint: disable=unused-argument return contains + def contains_course_runs(self, course_run_ids): # pylint: disable=unused-argument + """ + Determines if the given course runs are contained in this catalog. + + Arguments: + course_run_ids (str[]): List of course run IDs + + Returns: + dict: Mapping of course IDs to booleans indicating if course run is + contained in this catalog. + """ + contains = {course_run_id: False for course_run_id in course_run_ids} + course_runs = CourseRun.search(self.query).filter(key__in=course_run_ids).values_list('key', flat=True) + contains.update({course_run_id: course_run_id in course_runs for course_run_id in course_run_ids}) + + return contains + @property def viewers(self): """ Returns a QuerySet of users who have been granted explicit access to view this Catalog. diff --git a/course_discovery/apps/catalogs/tests/test_models.py b/course_discovery/apps/catalogs/tests/test_models.py index 4694f06e5e..9342c4fb5d 100644 --- a/course_discovery/apps/catalogs/tests/test_models.py +++ b/course_discovery/apps/catalogs/tests/test_models.py @@ -5,7 +5,7 @@ from course_discovery.apps.catalogs.tests import factories from course_discovery.apps.core.tests.factories import UserFactory from course_discovery.apps.core.tests.mixins import ElasticsearchTestMixin -from course_discovery.apps.course_metadata.tests.factories import CourseFactory +from course_discovery.apps.course_metadata.tests.factories import CourseFactory, CourseRunFactory @ddt.ddt @@ -39,6 +39,15 @@ def test_contains(self): {self.course.key: True, uncontained_course.key: False} ) + def test_contains_course_runs(self): + """ Verify the method returns a mapping of course run IDs to booleans. """ + course_run = CourseRunFactory(course=self.course) + uncontained_course_run = CourseRunFactory(title_override='ABD') + self.assertDictEqual( + self.catalog.contains_course_runs([course_run.key, uncontained_course_run.key]), + {course_run.key: True, uncontained_course_run.key: False} + ) + def test_courses_count(self): """ Verify the method returns the number of courses contained in the Catalog. """ self.assertEqual(self.catalog.courses_count, 1)