Skip to content

Commit 08950bf

Browse files
feat: keep courses in sync with CourseRun/CatalogCourse
1 parent 36647b4 commit 08950bf

1 file changed

Lines changed: 46 additions & 1 deletion

File tree

  • openedx/core/djangoapps/content/course_overviews

openedx/core/djangoapps/content/course_overviews/signals.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
Signal handler for invalidating cached course overviews
33
"""
44

5-
65
import logging
76

87
from django.db import transaction
98
from django.db.models.signals import post_save
109
from django.dispatch import Signal
1110
from django.dispatch.dispatcher import receiver
1211

12+
from openedx_catalog import api as catalog_api
13+
from openedx_catalog.models_api import CourseRun
1314
from openedx.core.djangoapps.signals.signals import COURSE_CERT_DATE_CHANGE
1415
from xmodule.data import CertificatesDisplayBehaviors
1516
from xmodule.modulestore.django import SignalHandler
@@ -33,6 +34,8 @@ def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable
3334
"""
3435
Catches the signal that a course has been published in Studio and updates the corresponding CourseOverview cache
3536
entry.
37+
38+
Also sync course data to the openedx_catalog CourseRun model.
3639
"""
3740
try:
3841
previous_course_overview = CourseOverview.objects.get(id=course_key)
@@ -41,6 +44,48 @@ def _listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable
4144
updated_course_overview = CourseOverview.load_from_module_store(course_key)
4245
_check_for_course_changes(previous_course_overview, updated_course_overview)
4346

47+
# Currently, SplitModulestoreCourseIndex is the ultimate source of truth for
48+
# which courses exist. When a course is published, we sync that data to
49+
# CourseOverview, and from CourseOverview to CourseRun.
50+
51+
# In the future, CourseRun will be the "source of truth" and each CourseRun
52+
# may optionally point to content and get synced to CourseOverview.
53+
54+
# Ensure a CourseRun exists for this course
55+
try:
56+
course_run = catalog_api.get_course_run(course_key)
57+
except CourseRun.DoesNotExist:
58+
# Presumably this is a newly-created course. Create the CourseRun.
59+
course_run = catalog_api.create_course_run_for_modulestore_course_with(
60+
course_id=course_key,
61+
display_name=updated_course_overview.display_name,
62+
language_short=updated_course_overview.language,
63+
)
64+
65+
# Keep the CourseRun up to date as the course is edited:
66+
if updated_course_overview.display_name != course_run.display_name:
67+
catalog_api.sync_course_run_details(course_key, display_name=updated_course_overview.display_name)
68+
69+
if (
70+
updated_course_overview.language
71+
and updated_course_overview.language != course_run.catalog_course.language_short
72+
):
73+
if course_run.catalog_course.runs.count() == 1:
74+
# This is the only run in this CatalogCourse. Update the language of the CatalogCourse
75+
catalog_api.update_catalog_course(
76+
course_run.catalog_course,
77+
language_short=updated_course_overview.language,
78+
)
79+
else:
80+
LOG.warning(
81+
'Course run "%s" language "%s" does not match its catalog course language, "%s"',
82+
str(course_key),
83+
updated_course_overview.language,
84+
course_run.catalog_course.language_short,
85+
)
86+
87+
# In the future, this will also sync schedule and other metadata to the CourseRun's related models
88+
4489

4590
@receiver(SignalHandler.course_deleted)
4691
def _listen_for_course_delete(sender, course_key, **kwargs): # pylint: disable=unused-argument

0 commit comments

Comments
 (0)