Exposing course name via Commerce API
The course now includes a read-only name attribute. XCOM-536
This commit is contained in:
committed by
Clinton Blackburn
parent
53db053c18
commit
880da5a09d
@@ -1,11 +1,11 @@
|
||||
""" API v1 models. """
|
||||
from itertools import groupby
|
||||
import logging
|
||||
|
||||
import logging
|
||||
from django.db import transaction
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from course_modes.models import CourseMode
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -22,6 +22,19 @@ class Course(object):
|
||||
self.modes = list(modes)
|
||||
self._deleted_modes = []
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" Return course name. """
|
||||
course_id = CourseKey.from_string(unicode(self.id)) # pylint: disable=invalid-name
|
||||
|
||||
try:
|
||||
return CourseOverview.get_from_id(course_id).display_name
|
||||
except CourseOverview.DoesNotExist:
|
||||
# NOTE (CCB): Ideally, the course modes table should only contain data for courses that exist in
|
||||
# modulestore. If that is not the case, say for local development/testing, carry on without failure.
|
||||
log.warning('Failed to retrieve CourseOverview for [%s]. Using empty course name.', course_id)
|
||||
return None
|
||||
|
||||
def get_mode_display_name(self, mode):
|
||||
""" Returns display name for the given mode. """
|
||||
slug = mode.mode_slug.strip().lower()
|
||||
|
||||
@@ -25,6 +25,7 @@ class CourseModeSerializer(serializers.ModelSerializer):
|
||||
class CourseSerializer(serializers.Serializer):
|
||||
""" Course serializer. """
|
||||
id = serializers.CharField() # pylint: disable=invalid-name
|
||||
name = serializers.CharField(read_only=True)
|
||||
modes = CourseModeSerializer(many=True, allow_add_remove=True)
|
||||
|
||||
def restore_object(self, attrs, instance=None):
|
||||
|
||||
@@ -47,6 +47,17 @@ class CourseApiViewTestMixin(object):
|
||||
u'expires': expires,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _serialize_course(cls, course, modes=None):
|
||||
""" Serializes a course to a Python dict. """
|
||||
modes = modes or []
|
||||
|
||||
return {
|
||||
u'id': unicode(course.id),
|
||||
u'name': unicode(course.display_name),
|
||||
u'modes': [cls._serialize_course_mode(mode) for mode in modes]
|
||||
}
|
||||
|
||||
|
||||
class CourseListViewTests(CourseApiViewTestMixin, ModuleStoreTestCase):
|
||||
""" Tests for CourseListView. """
|
||||
@@ -66,12 +77,7 @@ class CourseListViewTests(CourseApiViewTestMixin, ModuleStoreTestCase):
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
actual = json.loads(response.content)
|
||||
expected = [
|
||||
{
|
||||
u'id': unicode(self.course.id),
|
||||
u'modes': [self._serialize_course_mode(self.course_mode)]
|
||||
}
|
||||
]
|
||||
expected = [self._serialize_course(self.course, [self.course_mode])]
|
||||
self.assertListEqual(actual, expected)
|
||||
|
||||
|
||||
@@ -104,10 +110,7 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
actual = json.loads(response.content)
|
||||
expected = {
|
||||
u'id': unicode(self.course.id),
|
||||
u'modes': [self._serialize_course_mode(self.course_mode)]
|
||||
}
|
||||
expected = self._serialize_course(self.course, [self.course_mode])
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_retrieve_invalid_course(self):
|
||||
@@ -128,10 +131,8 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
|
||||
sku=u'ABC123',
|
||||
expiration_datetime=expiration_datetime
|
||||
)
|
||||
expected = {
|
||||
u'id': unicode(self.course.id),
|
||||
u'modes': [self._serialize_course_mode(expected_course_mode)]
|
||||
}
|
||||
expected = self._serialize_course(self.course, [expected_course_mode])
|
||||
|
||||
response = self.client.put(self.path, json.dumps(expected), content_type=JSON_CONTENT_TYPE)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -145,11 +146,8 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
|
||||
self.user.user_permissions.add(permission)
|
||||
|
||||
course_id = unicode(self.course.id)
|
||||
expected = {
|
||||
u'id': course_id,
|
||||
u'modes': [self._serialize_course_mode(
|
||||
CourseMode(mode_slug=u'credit', min_price=500, currency=u'USD', sku=u'ABC123')), ]
|
||||
}
|
||||
expected_course_mode = CourseMode(mode_slug=u'credit', min_price=500, currency=u'USD', sku=u'ABC123')
|
||||
expected = self._serialize_course(self.course, [expected_course_mode])
|
||||
path = reverse('commerce_api:v1:courses:retrieve_update', args=[course_id])
|
||||
response = self.client.put(path, json.dumps(expected), content_type=JSON_CONTENT_TYPE)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -190,19 +188,14 @@ class CourseRetrieveUpdateViewTests(CourseApiViewTestMixin, ModuleStoreTestCase)
|
||||
def assert_can_create_course(self, **request_kwargs):
|
||||
""" Verify a course can be created by the view. """
|
||||
course = CourseFactory.create()
|
||||
course_id = unicode(course.id)
|
||||
expected = {
|
||||
u'id': course_id,
|
||||
u'modes': [
|
||||
self._serialize_course_mode(
|
||||
CourseMode(mode_slug=u'verified', min_price=150, currency=u'USD', sku=u'ABC123')),
|
||||
self._serialize_course_mode(
|
||||
CourseMode(mode_slug=u'honor', min_price=0, currency=u'USD', sku=u'DEADBEEF')),
|
||||
]
|
||||
}
|
||||
path = reverse('commerce_api:v1:courses:retrieve_update', args=[course_id])
|
||||
expected_modes = [CourseMode(mode_slug=u'verified', min_price=150, currency=u'USD', sku=u'ABC123'),
|
||||
CourseMode(mode_slug=u'honor', min_price=0, currency=u'USD', sku=u'DEADBEEF')]
|
||||
expected = self._serialize_course(course, expected_modes)
|
||||
path = reverse('commerce_api:v1:courses:retrieve_update', args=[unicode(course.id)])
|
||||
|
||||
response = self.client.put(path, json.dumps(expected), content_type=JSON_CONTENT_TYPE, **request_kwargs)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
|
||||
actual = json.loads(response.content)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user