diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index e304606595..7fa3b50780 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -10,6 +10,7 @@ import requests from datetime import datetime import dateutil.parser from lazy import lazy +from base64 import b32encode from xmodule.exceptions import UndefinedContext from xmodule.seq_module import SequenceDescriptor, SequenceModule @@ -1398,3 +1399,12 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): self.video_upload_pipeline is not None and 'course_video_upload_token' in self.video_upload_pipeline ) + + def clean_id(self, padding_char='='): + """ + Returns a unique deterministic base32-encoded ID for the course. + The optional padding_char parameter allows you to override the "=" character used for padding. + """ + return "course_{}".format( + b32encode(unicode(self.location.course_key)).replace('=', padding_char) + ) diff --git a/lms/djangoapps/mobile_api/users/serializers.py b/lms/djangoapps/mobile_api/users/serializers.py index 9b12c054bf..e745d95de3 100644 --- a/lms/djangoapps/mobile_api/users/serializers.py +++ b/lms/djangoapps/mobile_api/users/serializers.py @@ -60,6 +60,7 @@ class CourseField(serializers.RelatedField): "course_updates": course_updates_url, "course_handouts": course_handouts_url, "course_about": course_about_url, + "subscription_id": course.clean_id(padding_char='_'), } diff --git a/lms/djangoapps/mobile_api/users/tests.py b/lms/djangoapps/mobile_api/users/tests.py index 1095e52a07..c5774fd593 100644 --- a/lms/djangoapps/mobile_api/users/tests.py +++ b/lms/djangoapps/mobile_api/users/tests.py @@ -60,6 +60,7 @@ class TestUserEnrollmentApi(MobileAPITestCase, MobileAuthUserTestMixin, MobileEn self.assertTrue('course_handouts' in found_course) self.assertEqual(found_course['id'], unicode(self.course.id)) self.assertEqual(courses[0]['mode'], 'honor') + self.assertEqual(courses[0]['course']['subscription_id'], self.course.clean_id(padding_char='_')) def verify_failure(self, response): self.assertEqual(response.status_code, 200) diff --git a/lms/djangoapps/mobile_api/users/views.py b/lms/djangoapps/mobile_api/users/views.py index 54f0089038..fa1e6c68ee 100644 --- a/lms/djangoapps/mobile_api/users/views.py +++ b/lms/djangoapps/mobile_api/users/views.py @@ -221,6 +221,7 @@ class UserCourseEnrollmentsList(generics.ListAPIView): * video_outline: The URI to get the list of all vides the user can access in the course. * id: The unique ID of the course. + * subscription_id: A unique "clean" (alphanumeric with '_') ID of the course. * latest_updates: Reserved for future use. * end: The end date of the course. * name: The name of the course.