diff --git a/openedx/core/djangoapps/discussions/handlers.py b/openedx/core/djangoapps/discussions/handlers.py index df718bda7cb6..d63e412afcc2 100644 --- a/openedx/core/djangoapps/discussions/handlers.py +++ b/openedx/core/djangoapps/discussions/handlers.py @@ -8,6 +8,7 @@ from openedx_events.learning.data import CourseDiscussionConfigurationData from openedx_events.learning.signals import COURSE_DISCUSSIONS_CHANGED +from openedx.core.djangoapps.course_apps.models import CourseAppStatus from openedx.core.djangoapps.discussions.models import ( DiscussionsConfiguration, DiscussionTopicLink, @@ -108,5 +109,14 @@ def update_course_discussion_config(configuration: CourseDiscussionConfiguration context_key=course_key, ).update(enabled=configuration.enabled) + # Also update CourseAppStatus to keep the Pages & Resources UI in sync. + # The update_course_apps_status task may run before this handler due to + # the COURSE_PUBLISH_TASK_DELAY countdown, caching a stale enabled value. + CourseAppStatus.update_status_for_course_app( + course_key=course_key, + app_id="discussion", + enabled=configuration.enabled, + ) + COURSE_DISCUSSIONS_CHANGED.connect(handle_course_discussion_config_update) diff --git a/openedx/core/djangoapps/discussions/migrations/0019_sync_discussion_config_enabled_with_tab.py b/openedx/core/djangoapps/discussions/migrations/0019_sync_discussion_config_enabled_with_tab.py new file mode 100644 index 000000000000..5a536370ddd8 --- /dev/null +++ b/openedx/core/djangoapps/discussions/migrations/0019_sync_discussion_config_enabled_with_tab.py @@ -0,0 +1,51 @@ +""" +Sync DiscussionsConfiguration.enabled and CourseAppStatus.enabled with +CourseOverviewTab.is_hidden. + +When a course is imported, the discussion tab's is_hidden value is carried over +from the source course. However, DiscussionsConfiguration.enabled and +CourseAppStatus.enabled default to True and are not updated from the imported +tab state, causing a desync. + +This migration reads each discussion tab from CourseOverviewTab (a DB cache of +course tabs) and sets both DiscussionsConfiguration.enabled and +CourseAppStatus.enabled to NOT is_hidden. +""" + +from django.db import migrations + + +def sync_enabled_from_course_overview_tab(apps, schema_editor): + CourseOverviewTab = apps.get_model("course_overviews", "CourseOverviewTab") + DiscussionsConfiguration = apps.get_model("discussions", "DiscussionsConfiguration") + CourseAppStatus = apps.get_model("course_apps", "CourseAppStatus") + + discussion_tabs = CourseOverviewTab.objects.filter(tab_id="discussion").select_related("course_overview") + + for tab in discussion_tabs.iterator(): + course_key = tab.course_overview_id + expected_enabled = not tab.is_hidden + DiscussionsConfiguration.objects.filter( + context_key=course_key, + ).exclude( + enabled=expected_enabled, + ).update(enabled=expected_enabled) + CourseAppStatus.objects.filter( + course_key=course_key, + app_id="discussion", + ).exclude( + enabled=expected_enabled, + ).update(enabled=expected_enabled) + + +class Migration(migrations.Migration): + + dependencies = [ + ("discussions", "0018_auto_20230904_1054"), + ("course_overviews", "0030_backfill_new_catalog_courseruns"), + ("course_apps", "0002_alter_historicalcourseappstatus_options"), + ] + + operations = [ + migrations.RunPython(sync_enabled_from_course_overview_tab, migrations.RunPython.noop), + ]