diff --git a/lms/djangoapps/grades/rest_api/v1/gradebook_views.py b/lms/djangoapps/grades/rest_api/v1/gradebook_views.py index d265074e4a..50d42a2f0f 100644 --- a/lms/djangoapps/grades/rest_api/v1/gradebook_views.py +++ b/lms/djangoapps/grades/rest_api/v1/gradebook_views.py @@ -583,25 +583,26 @@ class GradebookView(GradeViewMixin, PaginatedAPIView): if request.GET.get('course_grade_min') or request.GET.get('course_grade_max'): grade_conditions = {} q_object = Q() - if request.GET.get('course_grade_min'): + course_grade_min = request.GET.get('course_grade_min') + if course_grade_min: course_grade_min = float(request.GET.get('course_grade_min')) / 100 grade_conditions['percent_grade__gte'] = course_grade_min - if course_grade_min == 0: - subquery_grade_absent = ~Exists( - PersistentCourseGrade.objects.filter( - course_id=OuterRef('course'), - user_id=OuterRef('user_id'), - ) - ) - - annotations['course_grade_absent'] = subquery_grade_absent - q_object |= Q(course_grade_absent=True) - if request.GET.get('course_grade_max'): course_grade_max = float(request.GET.get('course_grade_max')) / 100 grade_conditions['percent_grade__lte'] = course_grade_max + if not course_grade_min or course_grade_min == 0: + subquery_grade_absent = ~Exists( + PersistentCourseGrade.objects.filter( + course_id=OuterRef('course'), + user_id=OuterRef('user_id'), + ) + ) + + annotations['course_grade_absent'] = subquery_grade_absent + q_object |= Q(course_grade_absent=True) + subquery_grade_in_range = Exists( PersistentCourseGrade.objects.filter( course_id=OuterRef('course'), diff --git a/lms/djangoapps/grades/rest_api/v1/tests/test_gradebook_views.py b/lms/djangoapps/grades/rest_api/v1/tests/test_gradebook_views.py index 4637c77f56..6ec932c64b 100644 --- a/lms/djangoapps/grades/rest_api/v1/tests/test_gradebook_views.py +++ b/lms/djangoapps/grades/rest_api/v1/tests/test_gradebook_views.py @@ -1152,7 +1152,7 @@ class GradebookViewTest(GradebookViewTestBase): ['login_course_staff', 5] ) @ddt.unpack - def test_filter_course_grade_absent(self, login_method, num_enrollments): + def test_filter_course_grade_absent_with_min(self, login_method, num_enrollments): with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade: # even though we're creating actual PersistentCourseGrades below, we still need # mocked subsection grades @@ -1210,6 +1210,70 @@ class GradebookViewTest(GradebookViewTestBase): self.assertEqual(actual_data['total_users_count'], num_enrollments) self.assertEqual(actual_data['filtered_users_count'], num_enrollments) + @ddt.data( + ['login_staff', 4], + ['login_course_admin', 5], + ['login_course_staff', 5] + ) + @ddt.unpack + def test_filter_course_grade_absent_without_min(self, login_method, num_enrollments): + with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade: + # even though we're creating actual PersistentCourseGrades below, we still need + # mocked subsection grades + mock_grade.side_effect = [ + self.mock_course_grade(self.student, passed=True, percent=0.0), + self.mock_course_grade(self.other_student, passed=False, percent=0.45), + self.mock_course_grade(self.program_student, passed=True, percent=0.75), + ] + + PersistentCourseGrade( + user_id=self.other_student.id, + course_id=self.course_key, + percent_grade=0.45 + ).save() + PersistentCourseGrade( + user_id=self.program_student.id, + course_id=self.course_key, + percent_grade=0.75 + ).save() + + with override_waffle_flag(self.waffle_flag, active=True): + getattr(self, login_method)() + resp = self.client.get( + self.get_url(course_key=self.course.id) + '?course_grade_max=80' + ) + + expected_results = [ + OrderedDict([ + ('user_id', self.student.id), + ('username', self.student.username), + ('email', ''), + ('percent', 0.0), + ('section_breakdown', self.expected_subsection_grades()), + ]), + OrderedDict([ + ('user_id', self.other_student.id), + ('username', self.other_student.username), + ('email', ''), + ('percent', 0.45), + ('section_breakdown', self.expected_subsection_grades()), + ]), + OrderedDict([ + ('user_id', self.program_student.id), + ('username', self.program_student.username), + ('email', ''), + ('external_user_key', 'program_user_key_0'), + ('percent', 0.75), + ('section_breakdown', self.expected_subsection_grades()), + ]) + ] + + self.assertEqual(status.HTTP_200_OK, resp.status_code) + actual_data = dict(resp.data) + self.assertEqual(expected_results, actual_data['results']) + self.assertEqual(actual_data['total_users_count'], num_enrollments) + self.assertEqual(actual_data['filtered_users_count'], num_enrollments) + @ddt.ddt class GradebookBulkUpdateViewTest(GradebookViewTestBase):