diff --git a/lms/djangoapps/course_structure_api/v0/tests.py b/lms/djangoapps/course_structure_api/v0/tests.py index b0d39e5f6f..d5f2825080 100644 --- a/lms/djangoapps/course_structure_api/v0/tests.py +++ b/lms/djangoapps/course_structure_api/v0/tests.py @@ -302,7 +302,7 @@ class CourseStructureTests(CourseDetailMixin, CourseViewTestsMixin, ModuleStoreT super(CourseStructureTests, self).setUp() # Ensure course structure exists for the course - update_course_structure(self.course.id) + update_course_structure(unicode(self.course.id)) def test_get(self): """ diff --git a/lms/djangoapps/course_structure_api/v0/views.py b/lms/djangoapps/course_structure_api/v0/views.py index 1e35f7275a..a50133a2d9 100644 --- a/lms/djangoapps/course_structure_api/v0/views.py +++ b/lms/djangoapps/course_structure_api/v0/views.py @@ -191,7 +191,7 @@ class CourseStructure(CourseViewMixin, RetrieveAPIView): return super(CourseStructure, self).retrieve(request, *args, **kwargs) except models.CourseStructure.DoesNotExist: # If we don't have data stored, generate it and return a 503. - models.update_course_structure.delay(self.course.id) + models.update_course_structure.delay(unicode(self.course.id)) return Response(status=503, headers={'Retry-After': '120'}) def get_object(self, queryset=None): diff --git a/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py b/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py index 882a1a2981..b8b0eb4dc5 100644 --- a/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py +++ b/openedx/core/djangoapps/content/course_structures/management/commands/generate_course_structure.py @@ -39,7 +39,7 @@ class Command(BaseCommand): for course_key in course_keys: try: - update_course_structure(course_key) + update_course_structure(unicode(course_key)) except Exception as e: logger.error('An error occurred while generating course structure for %s: %s', unicode(course_key), e) diff --git a/openedx/core/djangoapps/content/course_structures/models.py b/openedx/core/djangoapps/content/course_structures/models.py index 548aab9deb..7819aec3fc 100644 --- a/openedx/core/djangoapps/content/course_structures/models.py +++ b/openedx/core/djangoapps/content/course_structures/models.py @@ -4,7 +4,7 @@ import logging from celery.task import task from django.dispatch import receiver from model_utils.models import TimeStampedModel -from opaque_keys.edx.locator import CourseLocator +from opaque_keys.edx.keys import CourseKey from xmodule.modulestore.django import modulestore, SignalHandler from util.models import CompressedTextField @@ -60,7 +60,7 @@ def generate_course_structure(course_key): def listen_for_course_publish(sender, course_key, **kwargs): # Note: The countdown=0 kwarg is set to to ensure the method below does not attempt to access the course # before the signal emitter has finished all operations. This is also necessary to ensure all tests pass. - update_course_structure.delay(course_key, countdown=0) + update_course_structure.delay(unicode(course_key), countdown=0) @task() @@ -68,9 +68,12 @@ def update_course_structure(course_key): """ Regenerates and updates the course structure (in the database) for the specified course. """ - if not isinstance(course_key, CourseLocator): - logger.error('update_course_structure requires a CourseLocator. Given %s.', type(course_key)) - return + # Ideally we'd like to accept a CourseLocator; however, CourseLocator is not JSON-serializable (by default) so + # Celery's delayed tasks fail to start. For this reason, callers should pass the course key as a Unicode string. + if not isinstance(course_key, basestring): + raise ValueError('course_key must be a string. {} is not acceptable.'.format(type(course_key))) + + course_key = CourseKey.from_string(course_key) try: structure = generate_course_structure(course_key)