Merge pull request #21341 from edx/mroytman/EDUCATOR-4432-make-course-grade-filter-more-robust
make course grade filter robust against missing minimum filter as wel…
This commit is contained in:
@@ -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'),
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user