From bda102de515294c3c3f046670ab07a137bd1ef84 Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 19 Jan 2024 10:50:32 -0300 Subject: [PATCH] feat: Added --active option for reindex_courses --- .../management/commands/reindex_course.py | 35 ++++++++++++++++--- .../commands/tests/test_reindex_courses.py | 24 +++++++++++-- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/reindex_course.py b/cms/djangoapps/contentstore/management/commands/reindex_course.py index f5b6b9fadd..7431716995 100644 --- a/cms/djangoapps/contentstore/management/commands/reindex_course.py +++ b/cms/djangoapps/contentstore/management/commands/reindex_course.py @@ -4,6 +4,7 @@ import logging from textwrap import dedent from time import time +from datetime import date from django.core.management import BaseCommand, CommandError from elasticsearch import exceptions @@ -38,6 +39,9 @@ class Command(BaseCommand): parser.add_argument('--all', action='store_true', help='Reindex all courses') + parser.add_argument('--active', + action='store_true', + help='Reindex active courses only') parser.add_argument('--setup', action='store_true', help='Reindex all courses on developers stack setup') @@ -65,12 +69,17 @@ class Command(BaseCommand): """ course_ids = options['course_ids'] all_option = options['all'] + active_option = options['active'] setup_option = options['setup'] readable_option = options['warning'] index_all_courses_option = all_option or setup_option - if (not len(course_ids) and not index_all_courses_option) or (len(course_ids) and index_all_courses_option): # lint-amnesty, pylint: disable=len-as-condition - raise CommandError("reindex_course requires one or more s OR the --all or --setup flags.") + if ((not course_ids and not (index_all_courses_option or active_option)) or + (course_ids and (index_all_courses_option or active_option))): + raise CommandError(( + "reindex_course requires one or more s" + " OR the --all, --active or --setup flags." + )) store = modulestore() @@ -104,12 +113,28 @@ class Command(BaseCommand): course_keys = [course.id for course in modulestore().get_courses()] else: return + elif active_option: + # in case of --active, we get the list of course keys from all courses + # that are stored in the modulestore and filter out the non-active + course_keys = [] + + today = date.today() + all_courses = modulestore().get_courses() + for course in all_courses: + # Omitting courses without a start date as well as + # couses that already ended (end date is in the past) + if not course.start or (course.end and course.end.date() < today): + continue + course_keys.append(course.id) + + logging.warning(f'Selected {len(course_keys)} active courses over a total of {len(all_courses)}.') + else: # in case course keys are provided as arguments course_keys = list(map(self._parse_course_key, course_ids)) total = len(course_keys) - logging.warning(f'Reindexing {total} courses') + logging.warning(f'Reindexing {total} courses...') reindexed = 0 start = time() @@ -120,6 +145,6 @@ class Command(BaseCommand): if reindexed % 10 == 0 or reindexed == total: now = time() t = now - start - logging.warning(f'{reindexed}/{total} reindexed in {t:.1f} seconds') + logging.warning(f'{reindexed}/{total} reindexed in {t:.1f} seconds.') except Exception as exc: # lint-amnesty, pylint: disable=broad-except - logging.exception('Error indexing course %s due to the error: %s', course_key, exc) + logging.exception('Error indexing course %s due to the error: %s.', course_key, exc) 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 57534f30c4..8761cf760f 100644 --- a/cms/djangoapps/contentstore/management/commands/tests/test_reindex_courses.py +++ b/cms/djangoapps/contentstore/management/commands/tests/test_reindex_courses.py @@ -10,6 +10,7 @@ from xmodule.modulestore import ModuleStoreEnum # lint-amnesty, pylint: disable from xmodule.modulestore.django import modulestore # lint-amnesty, pylint: disable=wrong-import-order from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase # lint-amnesty, pylint: disable=wrong-import-order from xmodule.modulestore.tests.factories import CourseFactory, LibraryFactory # lint-amnesty, pylint: disable=wrong-import-order +from datetime import datetime, timedelta @ddt.ddt @@ -26,11 +27,18 @@ class TestReindexCourse(ModuleStoreTestCase): org="test", library="lib2", display_name="run2", default_store=ModuleStoreEnum.Type.split ) + yesterday = datetime.min.today() - timedelta(days=1) + self.first_course = CourseFactory.create( - org="test", course="course1", display_name="run1" + org="test", course="course1", display_name="run1", start=yesterday, end=None ) + self.second_course = CourseFactory.create( - org="test", course="course2", display_name="run1" + org="test", course="course2", display_name="run1", start=yesterday, end=yesterday + ) + + self.third_course = CourseFactory.create( + org="test", course="course3", display_name="run1", start=None, end=None ) REINDEX_PATH_LOCATION = ( @@ -103,7 +111,7 @@ class TestReindexCourse(ModuleStoreTestCase): call_command('reindex_course', all=True) patched_yes_no.assert_called_once_with(ReindexCommand.CONFIRMATION_PROMPT, default='no') - expected_calls = self._build_calls(self.first_course, self.second_course) + expected_calls = self._build_calls(self.first_course, self.second_course, self.third_course) self.assertCountEqual(patched_index.mock_calls, expected_calls) def test_given_all_key_prompts_and_reindexes_all_courses_cancelled(self): @@ -116,3 +124,13 @@ class TestReindexCourse(ModuleStoreTestCase): patched_yes_no.assert_called_once_with(ReindexCommand.CONFIRMATION_PROMPT, default='no') patched_index.assert_not_called() + + def test_given_active_key_prompt(self): + """ Test that reindexes all courses when --active key is given """ + + with mock.patch(self.REINDEX_PATH_LOCATION) as patched_index, \ + mock.patch(self.MODULESTORE_PATCH_LOCATION, mock.Mock(return_value=self.store)): + call_command('reindex_course', active=True) + + expected_calls = self._build_calls(self.first_course) + self.assertCountEqual(patched_index.mock_calls, expected_calls)