diff --git a/lms/djangoapps/instructor_task/config/waffle.py b/lms/djangoapps/instructor_task/config/waffle.py index 6d353b4622cb6f117372458e8dd0d10420eae225..134ece89523ea93e8e433c98f598e4e9fa159cfc 100644 --- a/lms/djangoapps/instructor_task/config/waffle.py +++ b/lms/djangoapps/instructor_task/config/waffle.py @@ -3,23 +3,36 @@ This module contains various configuration settings via waffle switches for the instructor_task app. """ +from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag, WaffleFlagNamespace, WaffleSwitchNamespace -from openedx.core.djangoapps.waffle_utils import WaffleFlagNamespace, WaffleSwitchNamespace - -WAFFLE_NAMESPACE = u'instructor_task' +WAFFLE_NAMESPACE = 'instructor_task' INSTRUCTOR_TASK_WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name=WAFFLE_NAMESPACE) WAFFLE_SWITCHES = WaffleSwitchNamespace(name=WAFFLE_NAMESPACE) # Waffle switches -OPTIMIZE_GET_LEARNERS_FOR_COURSE = u'optimize_get_learners_for_course' -GENERATE_GRADE_REPORT_VERIFIED_ONLY = u'generate_grade_report_for_verified_only' +OPTIMIZE_GET_LEARNERS_FOR_COURSE = 'optimize_get_learners_for_course' + +# Course override flags +GENERATE_PROBLEM_GRADE_REPORT_VERIFIED_ONLY = 'generate_problem_grade_report_verified_only' +GENERATE_COURSE_GRADE_REPORT_VERIFIED_ONLY = 'generate_course_grade_report_verified_only' def waffle_flags(): """ Returns the namespaced, cached, audited Waffle flags dictionary for Grades. """ - return {} + return { + GENERATE_PROBLEM_GRADE_REPORT_VERIFIED_ONLY: CourseWaffleFlag( + waffle_namespace=INSTRUCTOR_TASK_WAFFLE_FLAG_NAMESPACE, + flag_name=GENERATE_PROBLEM_GRADE_REPORT_VERIFIED_ONLY, + flag_undefined_default=False, + ), + GENERATE_COURSE_GRADE_REPORT_VERIFIED_ONLY: CourseWaffleFlag( + waffle_namespace=INSTRUCTOR_TASK_WAFFLE_FLAG_NAMESPACE, + flag_name=GENERATE_COURSE_GRADE_REPORT_VERIFIED_ONLY, + flag_undefined_default=False, + ), + } def optimize_get_learners_switch_enabled(): @@ -29,9 +42,19 @@ def optimize_get_learners_switch_enabled(): return WAFFLE_SWITCHES.is_enabled(OPTIMIZE_GET_LEARNERS_FOR_COURSE) -def generate_grade_report_for_verified_only(): +def problem_grade_report_verified_only(course_id): + """ + Returns True if problem grade reports should only + return rows for verified students in the given course, + False otherwise. + """ + return waffle_flags()[GENERATE_PROBLEM_GRADE_REPORT_VERIFIED_ONLY].is_enabled(course_id) + + +def course_grade_report_verified_only(course_id): """ - Returns True if waffle switch is enabled that indicates generate grading reports only for - verified learners. + Returns True if problem grade reports should only + return rows for verified students in the given course, + False otherwise. """ - return WAFFLE_SWITCHES.is_enabled(GENERATE_GRADE_REPORT_VERIFIED_ONLY) + return waffle_flags()[GENERATE_COURSE_GRADE_REPORT_VERIFIED_ONLY].is_enabled(course_id) diff --git a/lms/djangoapps/instructor_task/tasks_helper/grades.py b/lms/djangoapps/instructor_task/tasks_helper/grades.py index f21b728e8eabad1eda7fc8da0134f6a43f7bc862..7beead617f07d170ccb811ce5eadfde8bd84c911 100644 --- a/lms/djangoapps/instructor_task/tasks_helper/grades.py +++ b/lms/djangoapps/instructor_task/tasks_helper/grades.py @@ -29,8 +29,9 @@ from lms.djangoapps.grades.api import prefetch_course_and_subsection_grades from lms.djangoapps.instructor_analytics.basic import list_problem_responses from lms.djangoapps.instructor_analytics.csvs import format_dictlist from lms.djangoapps.instructor_task.config.waffle import ( - generate_grade_report_for_verified_only, - optimize_get_learners_switch_enabled + course_grade_report_verified_only, + optimize_get_learners_switch_enabled, + problem_grade_report_verified_only ) from lms.djangoapps.teams.models import CourseTeamMembership from lms.djangoapps.verify_student.services import IDVerificationService @@ -221,6 +222,7 @@ class _CourseGradeReportContext(object): self.action_name = action_name self.course_id = course_id self.task_progress = TaskProgress(self.action_name, total=None, start_time=time()) + self.report_for_verified_only = course_grade_report_verified_only(self.course_id) @lazy def course(self): @@ -312,7 +314,7 @@ class _ProblemGradeReportContext(object): self.task_input = _task_input self.action_name = action_name self.course_id = course_id - self.report_for_verified_only = generate_grade_report_for_verified_only() + self.report_for_verified_only = problem_grade_report_verified_only(self.course_id) self.task_progress = TaskProgress(self.action_name, total=None, start_time=time()) self.file_name = 'problem_grade_report' @@ -561,11 +563,9 @@ class CourseGradeReport(object): **filter_kwargs ).select_related('profile') yield users - course_id = context.course_id task_log_message = u'{}, Task type: {}'.format(context.task_info_string, context.action_name) - report_for_verified_only = generate_grade_report_for_verified_only() - return get_enrolled_learners_for_course(course_id=course_id, verified_only=report_for_verified_only) + return get_enrolled_learners_for_course(course_id=course_id, verified_only=context.report_for_verified_only) def _user_grades(self, course_grade, context): """ diff --git a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py index 54ca4a154ec43b1fe37d9506126f808e83fd529b..7cbfd0271eab6f09a734f1a4bed282c77ca9fd7e 100644 --- a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py +++ b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py @@ -81,7 +81,6 @@ from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls from xmodule.partitions.partitions import Group, UserPartition -from ..config.waffle import GENERATE_GRADE_REPORT_VERIFIED_ONLY from ..models import ReportStore from ..tasks_helper.utils import UPDATE_STATUS_FAILED, UPDATE_STATUS_SUCCEEDED @@ -89,7 +88,6 @@ _TEAMS_CONFIG = TeamsConfig({ 'max_size': 2, 'topics': [{'id': 'topic', 'name': 'Topic', 'description': 'A Topic'}], }) -SWITCH_GENERATE_GRADE_REPORT_VERIFIED_ONLY = '.'.join(['instructor_task', GENERATE_GRADE_REPORT_VERIFIED_ONLY]) class InstructorGradeReportTestCase(TestReportMixin, InstructorTaskCourseTestCase): @@ -411,7 +409,7 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase): RequestCache.clear_all_namespaces() - expected_query_count = 45 + expected_query_count = 46 with patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'): with check_mongo_calls(mongo_count): with self.assertNumQueries(expected_query_count): @@ -731,23 +729,26 @@ class TestProblemGradeReport(TestReportMixin, InstructorTaskModuleTestCase): ]) @patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task') - @override_switch(SWITCH_GENERATE_GRADE_REPORT_VERIFIED_ONLY, True) def test_single_problem_verified_student_only(self, _get_current_task): - student_verified = self.create_student(u'user_verified', mode='verified') - vertical = ItemFactory.create( - parent_location=self.problem_section.location, - category='vertical', - metadata={'graded': True}, - display_name='Problem Vertical' - ) - self.define_option_problem(u'Problem1', parent=vertical) + with patch( + 'lms.djangoapps.instructor_task.tasks_helper.grades.problem_grade_report_verified_only', + return_value=True, + ): + student_verified = self.create_student(u'user_verified', mode='verified') + vertical = ItemFactory.create( + parent_location=self.problem_section.location, + category='vertical', + metadata={'graded': True}, + display_name='Problem Vertical' + ) + self.define_option_problem(u'Problem1', parent=vertical) - self.submit_student_answer(self.student_1.username, u'Problem1', ['Option 1']) - self.submit_student_answer(student_verified.username, u'Problem1', ['Option 1']) - result = ProblemGradeReport.generate(None, None, self.course.id, None, 'graded') - self.assertDictContainsSubset( - {'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0}, result - ) + self.submit_student_answer(self.student_1.username, u'Problem1', ['Option 1']) + self.submit_student_answer(student_verified.username, u'Problem1', ['Option 1']) + result = ProblemGradeReport.generate(None, None, self.course.id, None, 'graded') + self.assertDictContainsSubset( + {'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0}, result + ) @patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task') def test_inactive_enrollment_included(self, _get_current_task): @@ -1708,28 +1709,31 @@ class TestGradeReport(TestReportMixin, InstructorTaskModuleTestCase): ) @patch('lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task') - @override_switch(SWITCH_GENERATE_GRADE_REPORT_VERIFIED_ONLY, True) def test_course_grade_with_verified_student_only(self, _get_current_task): """ Tests that course grade report has expected data when it is generated only for verified learners. """ - student_1 = self.create_student(u'user_honor') - student_verified = self.create_student(u'user_verified', mode='verified') - vertical = ItemFactory.create( - parent_location=self.problem_section.location, - category='vertical', - metadata={'graded': True}, - display_name='Problem Vertical' - ) - self.define_option_problem(u'Problem1', parent=vertical) + with patch( + 'lms.djangoapps.instructor_task.tasks_helper.grades.course_grade_report_verified_only', + return_value=True, + ): + student_1 = self.create_student(u'user_honor') + student_verified = self.create_student(u'user_verified', mode='verified') + vertical = ItemFactory.create( + parent_location=self.problem_section.location, + category='vertical', + metadata={'graded': True}, + display_name='Problem Vertical' + ) + self.define_option_problem(u'Problem1', parent=vertical) - self.submit_student_answer(student_1.username, u'Problem1', ['Option 1']) - self.submit_student_answer(student_verified.username, u'Problem1', ['Option 1']) - result = CourseGradeReport.generate(None, None, self.course.id, None, 'graded') - self.assertDictContainsSubset( - {'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0}, result - ) + self.submit_student_answer(student_1.username, u'Problem1', ['Option 1']) + self.submit_student_answer(student_verified.username, u'Problem1', ['Option 1']) + result = CourseGradeReport.generate(None, None, self.course.id, None, 'graded') + self.assertDictContainsSubset( + {'action_name': 'graded', 'attempted': 1, 'succeeded': 1, 'failed': 0}, result + ) @ddt.data(True, False) def test_fast_generation(self, create_non_zero_grade):