diff --git a/lms/djangoapps/grades/rest_api/v1/gradebook_views.py b/lms/djangoapps/grades/rest_api/v1/gradebook_views.py index 2c0175b47c..8235b45b24 100644 --- a/lms/djangoapps/grades/rest_api/v1/gradebook_views.py +++ b/lms/djangoapps/grades/rest_api/v1/gradebook_views.py @@ -556,7 +556,8 @@ class GradebookView(GradeViewMixin, PaginatedAPIView): users, course_key=course_key, collected_block_structure=course_data.collected_structure ): if not exc: - entries.append(self._gradebook_entry(user, course, graded_subsections, course_grade)) + entry = self._gradebook_entry(user, course, graded_subsections, course_grade) + entries.append(entry) serializer = StudentGradebookEntrySerializer(entries, many=True) return self.get_paginated_response(serializer.data) diff --git a/lms/djangoapps/grades/rest_api/v1/tests/mixins.py b/lms/djangoapps/grades/rest_api/v1/tests/mixins.py index 2db3d38949..7b12399351 100644 --- a/lms/djangoapps/grades/rest_api/v1/tests/mixins.py +++ b/lms/djangoapps/grades/rest_api/v1/tests/mixins.py @@ -77,12 +77,14 @@ class GradeViewTestMixin(SharedModuleStoreTestCase): created=self.date, ) - def _create_user_program_enrollments(self, *users): + def _create_user_program_enrollments(self, *users, **kwargs): + # supply mode for enrollment. Use 'masters' to create a masters track enrollment for index, user in enumerate(users): course_enrollment = CourseEnrollmentFactory( course_id=self.course.id, user=user, created=self.date, + mode=kwargs.get('mode', 'audit') ) program_enrollment = ProgramEnrollmentFactory( @@ -111,8 +113,14 @@ class GradeViewTestMixin(SharedModuleStoreTestCase): username='program_student', email='i_love_learning@example.com', ) + self.program_masters_student = UserFactory( + password=self.password, + username='program_masters_student', + email='i_love_learning@example.com', + ) self._create_user_enrollments(self.student, self.other_student) self._create_user_program_enrollments(self.program_student) + self._create_user_program_enrollments(self.program_masters_student, mode='masters') @classmethod def _create_test_course_with_default_grading_policy(cls, display_name, run): 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 fc805bb522..26914b878e 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 @@ -472,21 +472,21 @@ class GradebookViewTest(GradebookViewTestBase): OrderedDict([ ('user_id', self.student.id), ('username', self.student.username), - ('email', self.student.email), + ('email', ''), ('percent', 0.85), ('section_breakdown', self.expected_subsection_grades()), ]), OrderedDict([ ('user_id', self.other_student.id), ('username', self.other_student.username), - ('email', self.other_student.email), + ('email', ''), ('percent', 0.45), ('section_breakdown', self.expected_subsection_grades()), ]), OrderedDict([ ('user_id', self.program_student.id), ('username', self.program_student.username), - ('email', self.program_student.email), + ('email', ''), ('external_user_key', 'program_user_key_0'), ('percent', 0.75), ('section_breakdown', self.expected_subsection_grades()), @@ -603,7 +603,7 @@ class GradebookViewTest(GradebookViewTestBase): expected_results = OrderedDict([ ('user_id', self.student.id), ('username', self.student.username), - ('email', self.student.email), + ('email', ''), ('percent', 0.85), ('section_breakdown', self.expected_subsection_grades()), ]) @@ -686,7 +686,7 @@ class GradebookViewTest(GradebookViewTestBase): expected_results = OrderedDict([ ('user_id', self.student.id), ('username', self.student.username), - ('email', self.student.email), + ('email', ''), ('percent', 0.85), ('section_breakdown', self.expected_subsection_grades()), ]) @@ -717,7 +717,59 @@ class GradebookViewTest(GradebookViewTestBase): OrderedDict([ ('user_id', self.program_student.id), ('username', self.program_student.username), - ('email', self.program_student.email), + ('email', ''), + ('external_user_key', 'program_user_key_0'), + ('percent', 0.75), + ('section_breakdown', self.expected_subsection_grades()), + ]), + OrderedDict([ + ('user_id', self.program_masters_student.id), + ('username', self.program_masters_student.username), + ('email', self.program_masters_student.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.assertIsNone(actual_data['next']) + self.assertIsNone(actual_data['previous']) + self.assertEqual(expected_results, actual_data['results']) + + @ddt.data( + 'login_staff', + 'login_course_admin', + 'login_course_staff', + ) + def test_gradebook_data_filter_masters_track_username_contains(self, login_method): + with patch('lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read') as mock_grade: + mock_grade.return_value = self.mock_course_grade( + self.program_masters_student, passed=True, percent=0.75 + ) + + # need to create a masters track enrollment, which should return email + with override_waffle_flag(self.waffle_flag, active=True): + getattr(self, login_method)() + + # check username contains "program" + resp = self.client.get( + self.get_url(course_key=self.course.id, user_contains='program') + ) + expected_results = [ + 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()), + ]), + OrderedDict([ + ('user_id', self.program_masters_student.id), + ('username', self.program_masters_student.username), + ('email', self.program_masters_student.email), ('external_user_key', 'program_user_key_0'), ('percent', 0.75), ('section_breakdown', self.expected_subsection_grades()), @@ -752,7 +804,7 @@ class GradebookViewTest(GradebookViewTestBase): OrderedDict([ ('user_id', self.other_student.id), ('username', self.other_student.username), - ('email', self.other_student.email), + ('email', ''), ('percent', 0.85), ('section_breakdown', self.expected_subsection_grades()), ]), @@ -787,7 +839,15 @@ class GradebookViewTest(GradebookViewTestBase): OrderedDict([ ('user_id', self.program_student.id), ('username', self.program_student.username), - ('email', self.program_student.email), + ('email', ''), + ('external_user_key', 'program_user_key_0'), + ('percent', 0.75), + ('section_breakdown', self.expected_subsection_grades()), + ]), + OrderedDict([ + ('user_id', self.program_masters_student.id), + ('username', self.program_masters_student.username), + ('email', self.program_masters_student.email), ('external_user_key', 'program_user_key_0'), ('percent', 0.75), ('section_breakdown', self.expected_subsection_grades()), @@ -798,7 +858,8 @@ class GradebookViewTest(GradebookViewTestBase): actual_data = dict(resp.data) self.assertIsNone(actual_data['next']) self.assertIsNone(actual_data['previous']) - self.assertEqual(expected_results, actual_data['results']) + #self.assertEqual(expected_results, actual_data['results']) + assert expected_results == actual_data['results'] @ddt.data( 'login_staff', @@ -841,7 +902,7 @@ class GradebookViewTest(GradebookViewTestBase): OrderedDict([ ('user_id', self.student.id), ('username', self.student.username), - ('email', self.student.email), + ('email', ''), ('percent', 0.85), ('section_breakdown', self.expected_subsection_grades()), ]), diff --git a/lms/djangoapps/grades/rest_api/v1/tests/test_views.py b/lms/djangoapps/grades/rest_api/v1/tests/test_views.py index 60e45a164f..578a59bc60 100644 --- a/lms/djangoapps/grades/rest_api/v1/tests/test_views.py +++ b/lms/djangoapps/grades/rest_api/v1/tests/test_views.py @@ -46,7 +46,7 @@ class SingleUserGradesTests(GradeViewTestMixin, AuthAndScopesTestMixin, APITestC """ This method is required by AuthAndScopesTestMixin. """ expected_data = [{ 'username': self.student.username, - 'email': self.student.email, + 'email': '', 'letter_grade': None, 'percent': 0.0, 'course_id': str(self.course_key), @@ -87,7 +87,7 @@ class SingleUserGradesTests(GradeViewTestMixin, AuthAndScopesTestMixin, APITestC self.assertEqual(resp.status_code, status.HTTP_200_OK) expected_data = [{ 'username': self.student.username, - 'email': self.student.email, + 'email': '', 'course_id': str(self.course_key), 'passed': False, 'percent': 0.0, @@ -157,7 +157,7 @@ class SingleUserGradesTests(GradeViewTestMixin, AuthAndScopesTestMixin, APITestC self.assertEqual(resp.status_code, status.HTTP_200_OK) expected_data = { 'username': self.student.username, - 'email': self.student.email, + 'email': '', 'course_id': str(self.course_key), } @@ -232,7 +232,7 @@ class CourseGradesViewTest(GradeViewTestMixin, APITestCase): ('results', [ { 'username': self.student.username, - 'email': self.student.email, + 'email': '', 'course_id': str(self.course.id), 'passed': False, 'percent': 0.0, @@ -240,7 +240,7 @@ class CourseGradesViewTest(GradeViewTestMixin, APITestCase): }, { 'username': self.other_student.username, - 'email': self.other_student.email, + 'email': '', 'course_id': str(self.course.id), 'passed': False, 'percent': 0.0, @@ -248,7 +248,15 @@ class CourseGradesViewTest(GradeViewTestMixin, APITestCase): }, { 'username': self.program_student.username, - 'email': self.program_student.email, + 'email': '', + 'course_id': str(self.course.id), + 'passed': False, + 'percent': 0.0, + 'letter_grade': None, + }, + { + 'username': self.program_masters_student.username, + 'email': self.program_masters_student.email, 'course_id': str(self.course.id), 'passed': False, 'percent': 0.0, diff --git a/lms/djangoapps/grades/rest_api/v1/utils.py b/lms/djangoapps/grades/rest_api/v1/utils.py index d518431f83..0a7d26cb77 100644 --- a/lms/djangoapps/grades/rest_api/v1/utils.py +++ b/lms/djangoapps/grades/rest_api/v1/utils.py @@ -139,7 +139,11 @@ class GradeViewMixin(DeveloperErrorViewMixin): enrollments_in_course = enrollments_in_course.select_related(*related_models) paged_enrollments = self.paginate_queryset(enrollments_in_course) - return [enrollment.user for enrollment in paged_enrollments] + retlist = [] + for enrollment in paged_enrollments: + enrollment.user.enrollment_mode = enrollment.mode + retlist.append(enrollment.user) + return retlist def _serialize_user_grade(self, user, course_key, course_grade): """ @@ -147,7 +151,8 @@ class GradeViewMixin(DeveloperErrorViewMixin): """ return { 'username': user.username, - 'email': user.email, + # per business requirements, email should only be visible for students in masters track only + 'email': user.email if getattr(user, 'enrollment_mode', '') == 'masters' else '', 'course_id': str(course_key), 'passed': course_grade.passed, 'percent': course_grade.percent,