Example #1
0
    def setUp(self):
        super().setUp()
        dump_random_state()

        self.user = UserFactory(username=self.MOCK_USER_DATA["username"])
        self.client.login(username=self.user.username, password=USER_PASSWORD)

        self.course = CourseFactory(site=self.site)
        self.course_runs = CourseRunFactory.create_batch(3, course=self.course)

        self.user_grade_low = UserGradeFactory(
            username=self.MOCK_USER_DATA["username"],
            course_run=self.course_runs[0],
            letter_grade="A",
            percent_grade=0.70,
        )
        self.user_grade_high = UserGradeFactory(
            username=self.MOCK_USER_DATA["username"],
            course_run=self.course_runs[1],
            letter_grade="C",
            percent_grade=1.00,
        )
        self.user_grade_revoked_cert = UserGradeFactory(
            username=self.MOCK_USER_DATA["username"],
            course_run=self.course_runs[2],
            letter_grade="B",
            percent_grade=0.80,
        )

        self.course_certs = [
            CourseCertificateFactory(course_id=course_run.key, site=self.site) for course_run in self.course_runs
        ]
        self.credential_content_type = ContentType.objects.get(app_label="credentials", model="coursecertificate")
        self.program_cert = ProgramCertificateFactory(site=self.site)
        self.program_content_type = ContentType.objects.get(app_label="credentials", model="programcertificate")
        self.user_credentials = [
            UserCredentialFactory(
                username=self.MOCK_USER_DATA["username"],
                credential_content_type=self.credential_content_type,
                credential=course_cert,
            )
            for course_cert in self.course_certs
        ]
        self.user_credentials[2].status = UserCredential.REVOKED
        self.user_credentials[2].save()
        self.org_names = ["CCC", "AAA", "BBB"]
        self.orgs = [OrganizationFactory(name=name, site=self.site) for name in self.org_names]
        self.program = ProgramFactory(
            course_runs=self.course_runs,
            authoring_organizations=self.orgs,
            site=self.site,
            uuid=self.program_cert.program_uuid,
        )
        self.pcr = ProgramCertRecordFactory(program=self.program, user=self.user)

        self.pathway = PathwayFactory(site=self.site)
        self.pathway.programs.set([self.program])
Example #2
0
    def setUp(self):
        super().setUp()

        self.user = UserFactory(username=self.MOCK_USER_DATA['username'])
        self.client.login(username=self.user.username, password=USER_PASSWORD)

        self.course = CourseFactory(site=self.site)
        self.course_runs = [
            CourseRunFactory(course=self.course) for _ in range(3)
        ]

        self.user_grade_low = UserGradeFactory(
            username=self.MOCK_USER_DATA['username'],
            course_run=self.course_runs[0],
            letter_grade='A',
            percent_grade=0.70)
        self.user_grade_high = UserGradeFactory(
            username=self.MOCK_USER_DATA['username'],
            course_run=self.course_runs[1],
            letter_grade='C',
            percent_grade=1.00)
        self.user_grade_revoked_cert = UserGradeFactory(
            username=self.MOCK_USER_DATA['username'],
            course_run=self.course_runs[2],
            letter_grade='B',
            percent_grade=.80)

        self.course_certs = [
            CourseCertificateFactory(course_id=course_run.key, site=self.site)
            for course_run in self.course_runs
        ]
        self.credential_content_type = ContentType.objects.get(
            app_label='credentials', model='coursecertificate')
        self.user_credentials = [
            UserCredentialFactory(
                username=self.MOCK_USER_DATA['username'],
                credential_content_type=self.credential_content_type,
                credential=course_cert) for course_cert in self.course_certs
        ]
        self.user_credentials[2].status = UserCredential.REVOKED
        self.org_names = ['CCC', 'AAA', 'BBB']
        self.orgs = [
            OrganizationFactory(name=name, site=self.site)
            for name in self.org_names
        ]
        self.program = ProgramFactory(course_runs=self.course_runs,
                                      authoring_organizations=self.orgs,
                                      site=self.site)
Example #3
0
    def test_grade_view_throttling(self):
        """ Verify requests are throttled and a message is logged after limit. """
        with LogCapture() as log:
            course = CourseFactory(site=self.site)
            course_run = CourseRunFactory(course=course)
            data = {
                'username': '******',
                'course_run': course_run.key,
                'letter_grade': 'A',
                'percent_grade': 0.9,
                'verified': True,
            }
            grade = UserGradeFactory(
                course_run=course_run,
                username=self.user.username,
                letter_grade='C',
            )
            path = reverse('api:v2:grades-detail', kwargs={'pk': grade.id})
            self.authenticate_user(self.user)
            self.add_user_permission(self.user, 'change_usergrade')

            # All requests up to limit should be acceptable
            self.hit_rate_limit('grade_view', path, data)

            # Request after limit should NOT be acceptable
            response = getattr(self.client, 'put')(path, data=data)
            self.assertEqual(response.status_code, 429)
            assert_log_correct(
                log,
                'credentials.apps.api.v2.views',
                'WARNING',
                'Credentials API endpoint GradeViewSet is being throttled.',
            )
Example #4
0
    def test_course_run_order(self):
        """ Test that the course_runs are returned in the program order """
        new_course_run = CourseRunFactory()
        self.program.course_runs.add(new_course_run)  # pylint: disable=no-member
        UserGradeFactory(username=self.MOCK_USER_DATA['username'],
                         course_run=new_course_run,
                         letter_grade='C',
                         percent_grade=.70)
        new_course_cert = CourseCertificateFactory(
            course_id=new_course_run.key, site=self.site)
        UserCredentialFactory(
            username=self.MOCK_USER_DATA['username'],
            credential_content_type=self.credential_content_type,
            credential=new_course_cert)

        response = self.client.get(
            reverse('records:programs', kwargs={'uuid':
                                                self.program.uuid.hex}))
        grades = json.loads(response.context_data['record'])['grades']

        expected_course_run_keys = [
            course_run.key
            for course_run in [self.course_runs[1], new_course_run]
        ]
        actual_course_run_keys = [grade['course_id'] for grade in grades]

        self.assertEqual(expected_course_run_keys, actual_course_run_keys)
Example #5
0
    def test_create_with_existing_user_grade(self):
        """ Verify that, if a user has already been issued a grade, further attempts to issue the same grade
        will NOT create a new grade, but update the fields of the existing grade.
        """
        grade = UserGradeFactory(course_run=self.course_run)
        self.authenticate_user(self.user)
        self.add_user_permission(self.user, 'add_usergrade')

        # POSTing with modified data should update the existing UserGrade
        data = self.serialize_user_grade(grade)
        data['letter_grade'] = 'B'
        response = self.client.post(self.list_path, data=JSONRenderer().render(data), content_type=JSON_CONTENT_TYPE)
        self.assertEqual(response.status_code, 201)

        grade.refresh_from_db()
        self.assertEqual(grade.letter_grade, 'B')
        self.assertDictEqual(response.data, self.serialize_user_grade(grade))
Example #6
0
    def test_update(self, method):
        """ Verify the endpoint supports updating the status of a UserGrade, but no other fields. """
        grade = UserGradeFactory(
            course_run=self.course_run,
            username=self.user.username,
            letter_grade='C',
        )
        path = reverse('api:v2:grades-detail', kwargs={'pk': grade.id})

        # Verify users without the change permission are denied access
        self.assert_access_denied(self.user, method, path, data=self.data)

        self.authenticate_user(self.user)
        self.add_user_permission(self.user, 'change_usergrade')
        response = getattr(self.client, method)(path, data=self.data)

        grade.refresh_from_db()
        self.assertEqual(response.status_code, 200)
        self.assertEqual(grade.letter_grade, self.data['letter_grade'])
        self.assertDictEqual(response.data, self.serialize_user_grade(grade))
Example #7
0
    def test_course_run_no_credential(self):
        """ Adds a course run with no credential and tests that it does appear in the results """
        new_course_run = CourseRunFactory()
        self.program.course_runs.add(new_course_run)
        UserGradeFactory(
            username=self.MOCK_USER_DATA["username"], course_run=new_course_run, letter_grade="F", percent_grade=0.05
        )
        CourseCertificateFactory(course_id=new_course_run.key, site=self.site)

        response = self.client.get(reverse("records:private_programs", kwargs={"uuid": self.program.uuid.hex}))
        grades = json.loads(response.context_data["record"])["grades"]
        self.assertEqual(len(grades), 2)

        self.assertEqual(new_course_run.course.title, grades[1]["name"])
Example #8
0
    def test_to_representation(self):
        grade = UserGradeFactory()

        expected = {
            'id': grade.id,
            'username': grade.username,
            'course_run': grade.course_run.key,
            'letter_grade': grade.letter_grade,
            'percent_grade': str(grade.percent_grade),
            'verified': grade.verified,
            'created': grade.created.strftime(api_settings.DATETIME_FORMAT),
            'modified': grade.modified.strftime(api_settings.DATETIME_FORMAT),
        }
        actual = UserGradeSerializer(grade).data
        self.assertDictEqual(actual, expected)
Example #9
0
    def test_to_representation(self):
        grade = UserGradeFactory()

        expected = {
            "id": grade.id,
            "username": grade.username,
            "course_run": grade.course_run.key,
            "letter_grade": grade.letter_grade,
            "percent_grade": str(grade.percent_grade),
            "verified": grade.verified,
            "created": grade.created.strftime(api_settings.DATETIME_FORMAT),
            "modified": grade.modified.strftime(api_settings.DATETIME_FORMAT),
        }
        actual = UserGradeSerializer(grade).data
        self.assertDictEqual(actual, expected)
Example #10
0
    def course_run_no_credential(self):
        """ Adds a course run with no credential and tests that it doesn't appear in the results """
        new_course_run = CourseRunFactory()
        self.program.course_runs.add(new_course_run)  # pylint: disable=no-member
        UserGradeFactory(username=self.MOCK_USER_DATA['username'],
                         course_run=new_course_run,
                         letter_grade='F',
                         percent_grade=.05)
        CourseCertificateFactory(course_id=new_course_run.key, site=self.site)

        response = self.client.get(
            reverse('records:programs', kwargs={'uuid':
                                                self.program.uuid.hex}))
        grades = json.loads(response.context_data['record'])['grades']
        self.assertEqual(len(grades), 1)

        self.assertEqual(self.course_runs[1].key, grades[0]['course_id'])
Example #11
0
    def test_multiple_attempts_no_cert(self):
        """ Adds a course with two failed course_run attempts (no cert) and verifies that
        the course only shows up once """
        # Only superusers can view an empty program (we could add a real cert too here, but this is a more direct test)
        self.user.is_superuser = True
        self.user.save()

        new_course = CourseFactory(site=self.site)
        new_course_runs = CourseRunFactory.create_batch(2, course=new_course)
        _ = [UserGradeFactory(username=self.MOCK_USER_DATA['username'],
                              course_run=course_run,
                              letter_grade='F',
                              percent_grade=0.20) for course_run in new_course_runs]
        self.program.course_runs = new_course_runs
        response = self.client.get(reverse('records:private_programs', kwargs={'uuid': self.program.uuid.hex}))
        grades = json.loads(response.context_data['record'])['grades']
        self.assertEqual(len(grades), 1)

        self.assertEqual(new_course.title, grades[0]['name'])
Example #12
0
    def test_course_run_order(self):
        """ Test that the course_runs are returned in the program order """
        new_course_run = CourseRunFactory()
        self.program.course_runs.add(new_course_run)
        UserGradeFactory(
            username=self.MOCK_USER_DATA["username"], course_run=new_course_run, letter_grade="C", percent_grade=0.70
        )
        new_course_cert = CourseCertificateFactory(course_id=new_course_run.key, site=self.site)
        UserCredentialFactory(
            username=self.MOCK_USER_DATA["username"],
            credential_content_type=self.credential_content_type,
            credential=new_course_cert,
        )

        response = self.client.get(reverse("records:private_programs", kwargs={"uuid": self.program.uuid.hex}))
        grades = json.loads(response.context_data["record"])["grades"]

        expected_course_run_keys = [course_run.key for course_run in [self.course_runs[1], new_course_run]]
        actual_course_run_keys = [grade["course_id"] for grade in grades]

        self.assertEqual(expected_course_run_keys, actual_course_run_keys)
Example #13
0
 def test_protected_deletion(self):
     course_run = CourseRunFactory()
     UserGradeFactory(course_run=course_run)
     with self.assertRaises(ProtectedError):
         course_run.delete()