diff --git a/cms/djangoapps/contentstore/management/commands/reindex_course.py b/cms/djangoapps/contentstore/management/commands/reindex_course.py index 73e2346ab547..6e153cac50d4 100644 --- a/cms/djangoapps/contentstore/management/commands/reindex_course.py +++ b/cms/djangoapps/contentstore/management/commands/reindex_course.py @@ -29,6 +29,8 @@ class Command(BaseCommand): ./manage.py reindex_course ... - reindexes courses with provided keys ./manage.py reindex_course --all --warning - reindexes all available courses with quieter logging ./manage.py reindex_course --setup - reindexes all courses for devstack setup + ./manage.py reindex_course --from_inclusion_date - reindexes courses that start on or after + settings.COURSEWARE_SEARCH_INCLUSION_DATE (defaults to 2020-01-01 if that setting is unset) """ help = dedent(__doc__) CONFIRMATION_PROMPT = "Re-indexing all courses might be a time consuming operation. Do you want to continue?" @@ -45,7 +47,9 @@ def add_arguments(self, parser): help='Reindex active courses only') parser.add_argument('--from_inclusion_date', action='store_true', - help='Reindex courses with a start date greater than COURSEWARE_SEARCH_INCLUSION_DATE' + help='Reindex courses with a start date on or after ' + 'settings.COURSEWARE_SEARCH_INCLUSION_DATE (defaults to 2020-01-01 ' + 'if that setting is unset)' ) parser.add_argument('--setup', action='store_true', @@ -142,10 +146,15 @@ def handle(self, *args, **options): # pylint: disable=too-many-statements # the settings defined COURSEWARE_SEARCH_INCLUSION_DATE all_courses = modulestore().get_courses() - inclusion_date = datetime.strptime( - settings.FEATURES.get('COURSEWARE_SEARCH_INCLUSION_DATE', '2020-01-01'), - '%Y-%m-%d' - ) + configured_inclusion_date = settings.COURSEWARE_SEARCH_INCLUSION_DATE + if not configured_inclusion_date: + configured_inclusion_date = '2020-01-01' + logging.warning( + 'COURSEWARE_SEARCH_INCLUSION_DATE is not set; defaulting to %s for ' + '--from_inclusion_date filtering.', + configured_inclusion_date, + ) + inclusion_date = datetime.strptime(configured_inclusion_date, '%Y-%m-%d') # We keep the courses that has a start date and the start date is greater than the inclusion date active_courses = filter(lambda course: course.start and (course.start >= inclusion_date), all_courses) diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_reindex_courses.py b/cms/djangoapps/contentstore/management/commands/tests/test_reindex_courses.py index 6c733d0501a9..97b1984006fa 100644 --- a/cms/djangoapps/contentstore/management/commands/tests/test_reindex_courses.py +++ b/cms/djangoapps/contentstore/management/commands/tests/test_reindex_courses.py @@ -6,6 +6,7 @@ import ddt from django.core.management import CommandError, call_command +from django.test import override_settings from cms.djangoapps.contentstore.management.commands.reindex_course import Command as ReindexCommand from xmodule.modulestore import ModuleStoreEnum # pylint: disable=wrong-import-order @@ -148,9 +149,8 @@ def test_given_active_key_prompt(self): expected_calls = self._build_calls(self.first_course, self.fourth_course) self.assertCountEqual(patched_index.mock_calls, expected_calls) # noqa: PT009 - @mock.patch.dict( - 'django.conf.settings.FEATURES', - {'COURSEWARE_SEARCH_INCLUSION_DATE': (datetime.min.today() - timedelta(weeks=52)).strftime('%Y-%m-%d')} + @override_settings( + COURSEWARE_SEARCH_INCLUSION_DATE=(datetime.min.today() - timedelta(weeks=52)).strftime('%Y-%m-%d') ) def test_given_from_inclusion_date_key_prompt(self): """ @@ -163,3 +163,19 @@ def test_given_from_inclusion_date_key_prompt(self): expected_calls = self._build_calls(self.first_course, self.second_course) self.assertCountEqual(patched_index.mock_calls, expected_calls) # noqa: PT009 + + @override_settings(COURSEWARE_SEARCH_INCLUSION_DATE=None) + def test_from_inclusion_date_warns_and_defaults_when_unset(self): + """ + Test that --from_inclusion_date logs a warning and falls back to the 2020-01-01 + floor (reindexing every course that starts on or after that date) when + COURSEWARE_SEARCH_INCLUSION_DATE is not configured. + """ + with mock.patch(self.REINDEX_PATH_LOCATION) as patched_index, \ + mock.patch(self.MODULESTORE_PATCH_LOCATION, mock.Mock(return_value=self.store)), \ + self.assertLogs(level='WARNING') as logs: + call_command('reindex_course', from_inclusion_date=True) + + assert any('COURSEWARE_SEARCH_INCLUSION_DATE is not set' in message for message in logs.output) + expected_calls = self._build_calls(self.first_course, self.second_course, self.fourth_course) + self.assertCountEqual(patched_index.mock_calls, expected_calls) # noqa: PT009 diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index dbf4b8e24689..b7ca242a4c4e 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -3224,7 +3224,7 @@ def test_is_mfe_search_waffle_disabled(self): self.assertEqual(response.status_code, 200) # noqa: PT009 self.assertEqual(body, {'enabled': False}) # noqa: PT009 - @patch.dict('django.conf.settings.FEATURES', {'COURSEWARE_SEARCH_INCLUSION_DATE': '2020'}) + @override_settings(COURSEWARE_SEARCH_INCLUSION_DATE='2020') @override_waffle_flag(COURSEWARE_MICROFRONTEND_SEARCH_ENABLED, active=False) @ddt.data( (datetime(2013, 9, 18, 11, 30, 00), False), diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 6cae5ec93aa3..8bc3725754cd 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -2355,7 +2355,7 @@ def courseware_mfe_search_enabled(request, course_id=None): else: has_required_enrollment = True - inclusion_date = settings.FEATURES.get('COURSEWARE_SEARCH_INCLUSION_DATE') + inclusion_date = settings.COURSEWARE_SEARCH_INCLUSION_DATE start_date = CourseOverview.get_from_id(course_key).start has_valid_inclusion_date = False diff --git a/openedx/envs/common.py b/openedx/envs/common.py index 1416eb6636d2..e4326a9fa81d 100644 --- a/openedx/envs/common.py +++ b/openedx/envs/common.py @@ -1172,6 +1172,16 @@ def add_optional_apps(optional_apps, installed_apps): # redirect URLs site-wide. Usually left empty and overridden per-site via site configuration. THIRD_PARTY_AUTH_HINT = '' +# .. setting_name: COURSEWARE_SEARCH_INCLUSION_DATE +# .. setting_default: None +# .. setting_description: YYYY-MM-DD cutoff date used to roll out courseware search to newer courses. +# In the LMS, the courseware-search-enabled endpoint exposes search for any course whose start date +# is after this date (in addition to any course where the courseware.mfe_courseware_search waffle +# flag is enabled); leaving it None disables this date-based rollout. The Studio +# `reindex_course --from_inclusion_date` command reindexes courses starting on/after this date, +# flooring an unset value at 2020-01-01 so the standalone command still has a bound to filter by. +COURSEWARE_SEARCH_INCLUSION_DATE = None + # .. toggle_name: CERTIFICATES_HTML_VIEW # .. toggle_implementation: DjangoSetting # .. toggle_default: False