diff --git a/lms/djangoapps/courseware/grades.py b/lms/djangoapps/courseware/grades.py index a7bcc8a8e3..5b1a9741d5 100644 --- a/lms/djangoapps/courseware/grades.py +++ b/lms/djangoapps/courseware/grades.py @@ -15,6 +15,7 @@ from django.core.cache import cache import dogstats_wrapper as dog_stats_api from courseware import courses +from courseware.access import has_access from courseware.model_data import FieldDataCache, ScoresClient from student.models import anonymous_id_for_user from util.module_utils import yield_dynamic_descriptor_descendants @@ -405,6 +406,10 @@ def _grade(student, request, course, keep_raw_scores, field_data_cache, scores_c descendants = yield_dynamic_descriptor_descendants(section_descriptor, student.id, create_module) for module_descriptor in descendants: + user_access = has_access(student, 'load', module_descriptor, module_descriptor.location.course_key) + if not user_access: + continue + (correct, total) = get_score( student, module_descriptor, diff --git a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py index c6701ebc55..fe74ba6f37 100644 --- a/lms/djangoapps/instructor_task/tests/test_tasks_helper.py +++ b/lms/djangoapps/instructor_task/tests/test_tasks_helper.py @@ -9,6 +9,7 @@ Tests that CSV grade report generation works with unicode emails. import ddt from mock import Mock, patch import tempfile +from openedx.core.djangoapps.course_groups import cohorts import unicodecsv from django.core.urlresolvers import reverse from django.test.utils import override_settings @@ -662,7 +663,7 @@ class TestProblemReportCohortedContent(TestReportMixin, ContentGroupTestCase, In """ def setUp(self): super(TestProblemReportCohortedContent, self).setUp() - # contstruct cohorted problems to work on. + # construct cohorted problems to work on. self.add_course_content() vertical = ItemFactory.create( parent_location=self.problem_section.location, @@ -681,6 +682,23 @@ class TestProblemReportCohortedContent(TestReportMixin, ContentGroupTestCase, In group_access={self.course.user_partitions[0].id: [self.course.user_partitions[0].groups[1].id]} ) + def _format_user_grade(self, header_row, user, grade): + """ + Helper method that format the user grade + Args: + header_row(list): header row of csv containing Student ID, Email, Username etc + user(object): Django user object + grade(list): Users' grade list + """ + return dict(zip( + header_row, + [ + unicode(user.id), + user.email, + user.username, + ] + grade + )) + def test_cohort_content(self): self.submit_student_answer(self.alpha_user.username, u'Pröblem0', ['Option 1', 'Option 1']) resp = self.submit_student_answer(self.alpha_user.username, u'Pröblem1', ['Option 1', 'Option 1']) @@ -695,49 +713,75 @@ class TestProblemReportCohortedContent(TestReportMixin, ContentGroupTestCase, In self.assertDictContainsSubset( {'action_name': 'graded', 'attempted': 4, 'succeeded': 4, 'failed': 0}, result ) - problem_names = [u'Homework 1: Problem - Pröblem0', u'Homework 1: Problem - Pröblem1'] header_row = [u'Student ID', u'Email', u'Username', u'Final Grade'] for problem in problem_names: header_row += [problem + ' (Earned)', problem + ' (Possible)'] - self.verify_rows_in_csv([ - dict(zip( - header_row, - [ - unicode(self.staff_user.id), - self.staff_user.email, - self.staff_user.username, u'0.0', u'N/A', u'N/A', u'N/A', u'N/A' - ] - )), - dict(zip( - header_row, - [ - unicode(self.alpha_user.id), - self.alpha_user.email, - self.alpha_user.username, - u'1.0', u'2.0', u'2.0', u'N/A', u'N/A' - ] - )), - dict(zip( - header_row, - [ - unicode(self.beta_user.id), - self.beta_user.email, - self.beta_user.username, - u'0.5', u'N/A', u'N/A', u'1.0', u'2.0' - ] - )), - dict(zip( - header_row, - [ - unicode(self.non_cohorted_user.id), - self.non_cohorted_user.email, - self.non_cohorted_user.username, - u'0.0', u'N/A', u'N/A', u'N/A', u'N/A' - ] - )), - ]) + user_grades = [ + {'user': self.staff_user, 'grade': [u'0.0', u'N/A', u'N/A', u'N/A', u'N/A']}, + {'user': self.alpha_user, 'grade': [u'1.0', u'2.0', u'2.0', u'N/A', u'N/A']}, + {'user': self.beta_user, 'grade': [u'0.5', u'N/A', u'N/A', u'1.0', u'2.0']}, + {'user': self.non_cohorted_user, 'grade': [u'0.0', u'N/A', u'N/A', u'N/A', u'N/A']}, + ] + + # Verify generated grades and expected grades match + expected_grades = [self._format_user_grade(header_row, **user_grade) for user_grade in user_grades] + self.verify_rows_in_csv(expected_grades) + + @patch('courseware.grades.MaxScoresCache.get', Mock(return_value=1)) + def test_cohort_content_with_maxcache(self): + """ + Tests the cohoted course grading to test the scenario in which `max_scores_cache` is set for the course + problems. + """ + # Course is cohorted + self.assertTrue(cohorts.is_course_cohorted(self.course.id)) + + # Verify user groups + self.assertEquals( + cohorts.get_cohort(self.alpha_user, self.course.id).id, + self.course.user_partitions[0].groups[0].id, + "alpha_user should be assigned to the correct cohort" + ) + self.assertEquals( + cohorts.get_cohort(self.beta_user, self.course.id).id, + self.course.user_partitions[0].groups[1].id, + "beta_user should be assigned to the correct cohort" + ) + + # Verify user enrollment + for user in [self.alpha_user, self.beta_user, self.non_cohorted_user]: + self.assertTrue(CourseEnrollment.is_enrolled(user, self.course.id)) + + self.submit_student_answer(self.alpha_user.username, u'Pröblem0', ['Option 1', 'Option 1']) + resp = self.submit_student_answer(self.alpha_user.username, u'Pröblem1', ['Option 1', 'Option 1']) + self.assertEqual(resp.status_code, 404) + + resp = self.submit_student_answer(self.beta_user.username, u'Pröblem0', ['Option 1', 'Option 2']) + self.assertEqual(resp.status_code, 404) + self.submit_student_answer(self.beta_user.username, u'Pröblem1', ['Option 1', 'Option 2']) + + with patch('instructor_task.tasks_helper._get_current_task'): + result = upload_problem_grade_report(None, None, self.course.id, None, 'graded') + self.assertDictContainsSubset( + {'action_name': 'graded', 'attempted': 4, 'succeeded': 4, 'failed': 0}, result + ) + problem_names = [u'Homework 1: Problem - Pröblem0', u'Homework 1: Problem - Pröblem1'] + header_row = [u'Student ID', u'Email', u'Username', u'Final Grade'] + for problem in problem_names: + header_row += [problem + ' (Earned)', problem + ' (Possible)'] + + user_grades = [ + {'user': self.staff_user, 'grade': [u'0.0', u'N/A', u'N/A', u'N/A', u'N/A']}, + {'user': self.alpha_user, 'grade': [u'1.0', u'2.0', u'2.0', u'N/A', u'N/A']}, + {'user': self.beta_user, 'grade': [u'0.5', u'N/A', u'N/A', u'1.0', u'2.0']}, + {'user': self.non_cohorted_user, 'grade': [u'0.0', u'N/A', u'N/A', u'N/A', u'N/A']}, + ] + + # Verify generated grades and expected grades match + expected_grades = [self._format_user_grade(header_row, **grade) for grade in user_grades] + self.verify_rows_in_csv(expected_grades) @ddt.ddt