示例#1
0
    def test_failing_grade_allowlist(self):
        # User who is not on the allowlist
        GeneratedCertificateFactory(
            user=self.user,
            course_id=self.course.id,
            status=CertificateStatuses.downloadable
        )
        CourseGradeFactory().update(self.user, self.course)
        cert = GeneratedCertificate.certificate_for_student(self.user, self.course.id)
        assert cert.status == CertificateStatuses.notpassing

        # User who is on the allowlist
        u = UserFactory.create()
        c = CourseFactory()
        course_key = c.id  # pylint: disable=no-member
        CertificateAllowlistFactory(
            user=u,
            course_id=course_key
        )
        GeneratedCertificateFactory(
            user=u,
            course_id=course_key,
            status=CertificateStatuses.downloadable
        )
        CourseGradeFactory().update(u, c)
        cert = GeneratedCertificate.certificate_for_student(u, course_key)
        assert cert.status == CertificateStatuses.downloadable
示例#2
0
def listen_for_passing_grade(sender, user, course_id, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a signal indicating that the user has passed a course run.

    If needed, generate a certificate task.
    """
    if not auto_certificate_generation_enabled():
        return

    cert = GeneratedCertificate.certificate_for_student(user, course_id)
    if cert is not None and CertificateStatuses.is_passing_status(cert.status):
        log.info(
            f'The cert status is already passing for user {user.id} : {course_id}. Passing grade signal will be '
            f'ignored.')
        return
    log.info(
        f'Attempt will be made to generate a course certificate for {user.id} : {course_id} as a passing grade '
        f'was received.')
    try:
        return generate_certificate_task(user, course_id)
    except CertificateGenerationNotAllowed as e:
        log.exception(
            "Certificate generation not allowed for user %s in course %s",
            str(user),
            course_id,
        )
        return False
示例#3
0
    def test_ineligible_cert_whitelisted(self, disable_audit_cert, status):
        """
        Test that audit mode students receive a certificate if DISABLE_AUDIT_CERTIFICATES
        feature is set to false
        """
        # Enroll as audit
        CourseEnrollmentFactory(user=self.user_2,
                                course_id=self.course.id,
                                is_active=True,
                                mode='audit')
        # Whitelist student
        CertificateWhitelistFactory(course_id=self.course.id, user=self.user_2)

        features = settings.FEATURES
        features['DISABLE_AUDIT_CERTIFICATES'] = disable_audit_cert
        with override_settings(FEATURES=features) and mock_passing_grade():
            with patch.object(XQueueInterface, 'send_to_queue') as mock_send:
                mock_send.return_value = (0, None)
                self.xqueue.add_cert(self.user_2, self.course.id)

        certificate = GeneratedCertificate.certificate_for_student(
            self.user_2, self.course.id)
        self.assertIsNotNone(certificate)
        self.assertEqual(certificate.mode, 'audit')
        self.assertEqual(certificate.status, status)
def _set_v2_cert_status(user, course_key):
    """
    Determine the V2 certificate status for this user, in this course run.

    This is used when a downloadable cert cannot be generated, but we want to provide more info about why it cannot
    be generated.
    """
    if not _can_set_v2_cert_status(user, course_key):
        return None

    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    status = _get_cert_status_common(user, course_key, cert)
    if status is not None:
        return status

    course_grade = _get_course_grade(user, course_key)
    if not course_grade.passed:
        if cert is None:
            cert = GeneratedCertificate.objects.create(user=user,
                                                       course_id=course_key)
        if cert.status != CertificateStatuses.notpassing:
            cert.mark_notpassing(course_grade.percent)
        return CertificateStatuses.notpassing

    return None
def _set_regular_cert_status(user, course_key, enrollment_mode, course_grade):
    """
    Determine the regular (non-allowlist) certificate status for this user, in this course run.

    This is used when a downloadable cert cannot be generated, but we want to provide more info about why it cannot
    be generated.
    """
    if not _can_set_regular_cert_status(user, course_key, enrollment_mode):
        return None

    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    status = _get_cert_status_common(user, course_key, enrollment_mode,
                                     course_grade, cert)
    if status is not None:
        return status

    if not _required_verification_missing(user) \
            and not _is_passing_grade(course_grade) \
            and cert is not None:
        if cert.status != CertificateStatuses.notpassing:
            course_grade_val = _get_grade_value(course_grade)
            cert.mark_notpassing(mode=enrollment_mode,
                                 grade=course_grade_val,
                                 source='certificate_generation')
        return CertificateStatuses.notpassing

    return None
示例#6
0
def listen_for_passing_grade(sender, user, course_id, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a signal indicating that the user has passed a course run.

    If needed, generate a certificate task.
    """
    if not auto_certificate_generation_enabled():
        return

    if can_generate_certificate_task(user, course_id):
        cert = GeneratedCertificate.certificate_for_student(user, course_id)
        if cert is not None and CertificateStatuses.is_passing_status(
                cert.status):
            log.info(
                f'{course_id} is using V2 certificates, and the cert status is already passing for user '
                f'{user.id}. Passing grade signal will be ignored.')
            return
        log.info(
            f'{course_id} is using V2 certificates. Attempt will be made to generate a V2 certificate for '
            f'{user.id} as a passing grade was received.')
        return generate_certificate_task(user, course_id)

    if _fire_ungenerated_certificate_task(user, course_id):
        log.info(
            'Certificate generation task initiated for {user} : {course} via passing grade'
            .format(user=user.id, course=course_id))
示例#7
0
def _fire_ungenerated_certificate_task(user,
                                       course_key,
                                       expected_verification_status=None):
    """
    Helper function to fire certificate generation task.
    Auto-generation of certificates is available for following course modes:
        1- VERIFIED
        2- CREDIT_MODE
        3- PROFESSIONAL
        4- NO_ID_PROFESSIONAL_MODE

    Certificate generation task is fired to either generate a certificate
    when there is no generated certificate for user in a particular course or
    update a certificate if it has 'unverified' status.

    Task is fired to attempt an update to a certificate
    with 'unverified' status as this method is called when a user is
    successfully verified, any certificate associated
    with such user can now be verified.

    NOTE: Purpose of restricting other course modes (HONOR and AUDIT) from auto-generation is to reduce
    traffic to workers.
    """

    message = u'Entered into Ungenerated Certificate task for {user} : {course}'
    log.info(message.format(user=user.id, course=course_key))

    allowed_enrollment_modes_list = [
        CourseMode.VERIFIED,
        CourseMode.CREDIT_MODE,
        CourseMode.PROFESSIONAL,
        CourseMode.NO_ID_PROFESSIONAL_MODE,
        CourseMode.MASTERS,
        CourseMode.EXECUTIVE_EDUCATION,
    ]
    enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(
        user, course_key)
    cert = GeneratedCertificate.certificate_for_student(user, course_key)

    generate_learner_certificate = (
        enrollment_mode in allowed_enrollment_modes_list
        and (cert is None or cert.status == 'unverified'))

    if generate_learner_certificate:
        kwargs = {
            'student': six.text_type(user.id),
            'course_key': six.text_type(course_key)
        }
        if expected_verification_status:
            kwargs['expected_verification_status'] = six.text_type(
                expected_verification_status)
        generate_certificate.apply_async(countdown=CERTIFICATE_DELAY_SECONDS,
                                         kwargs=kwargs)
        return True

    message = u'Certificate Generation task failed for {user} : {course}'
    log.info(message.format(user=user.id, course=course_key))
    return False
示例#8
0
 def get_certificate(self, user_id, course_id):
     """
         Check if user has generated a certificate
     """
     certificate = GeneratedCertificate.certificate_for_student(
         user_id, course_id)
     if certificate is None:
         return 'No'
     return 'Si'
示例#9
0
 def test_cert_failure(self, status):
     if CertificateStatuses.is_passing_status(status):
         expected_status = CertificateStatuses.notpassing
     else:
         expected_status = status
     GeneratedCertificate.eligible_certificates.create(
         user=self.user, course_id=self.course.id, status=status)
     CourseGradeFactory().update(self.user, self.course)
     cert = GeneratedCertificate.certificate_for_student(
         self.user, self.course.id)
     self.assertEqual(cert.status, expected_status)
示例#10
0
def get_certificate_for_user_id(user, course_id):
    """
    Retrieve certificate information for a user in a specific course.

    Arguments:
        user (User): A Django User.
        course_id (CourseKey): Course ID
    Returns:
        A GeneratedCertificate object.
    """
    return GeneratedCertificate.certificate_for_student(user, course_id)
示例#11
0
def _set_allowlist_cert_status(user, course_key):
    """
    Determine the allowlist certificate status for this user, in this course run and update the cert.

    This is used when a downloadable cert cannot be generated, but we want to provide more info about why it cannot
    be generated.
    """
    if not _can_set_allowlist_cert_status(user, course_key):
        return None

    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    return _get_cert_status_common(user, course_key, cert)
示例#12
0
def can_generate_allowlist_certificate(user, course_key):
    """
    Check if an allowlist certificate can be generated (created if it doesn't already exist, or updated if it does
    exist) for this user, in this course run.
    """
    if not is_using_certificate_allowlist(course_key):
        # This course run is not using the allowlist feature
        log.info(
            '{course} is not using the certificate allowlist. Certificate cannot be generated.'.format(
                course=course_key
            ))
        return False

    if not auto_certificate_generation_enabled():
        # Automatic certificate generation is globally disabled
        log.info('Automatic certificate generation is globally disabled. Certificate cannot be generated.')
        return False

    if CertificateInvalidation.has_certificate_invalidation(user, course_key):
        # The invalidation list overrides the allowlist
        log.info(
            '{user} : {course} is on the certificate invalidation list. Certificate cannot be generated.'.format(
                user=user.id,
                course=course_key
            ))
        return False

    enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(user, course_key)
    if enrollment_mode is None:
        log.info('{user} : {course} does not have an enrollment. Certificate cannot be generated.'.format(
            user=user.id,
            course=course_key
        ))
        return False

    if not IDVerificationService.user_has_ever_been_verified(user):
        log.info(f'{user.id} has not ever had a verified id. Certificate cannot be generated.')
        return False

    if not _is_on_certificate_allowlist(user, course_key):
        log.info('{user} : {course} is not on the certificate allowlist. Certificate cannot be generated.'.format(
            user=user.id,
            course=course_key
        ))
        return False

    log.info('{user} : {course} is on the certificate allowlist'.format(
        user=user.id,
        course=course_key
    ))
    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    return _can_generate_allowlist_certificate_for_status(cert)
示例#13
0
 def test_cert_failure(self, status):
     if CertificateStatuses.is_passing_status(status):
         expected_status = CertificateStatuses.notpassing
     else:
         expected_status = status
     GeneratedCertificate.eligible_certificates.create(
         user=self.user,
         course_id=self.course.id,
         status=status
     )
     CourseGradeFactory().update(self.user, self.course)
     cert = GeneratedCertificate.certificate_for_student(self.user, self.course.id)
     self.assertEqual(cert.status, expected_status)
def _is_cert_downloadable(user, course_key):
    """
    Check if cert already exists, has a downloadable status, and has not been invalidated
    """
    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    if cert is None:
        return False
    if cert.status != CertificateStatuses.downloadable:
        return False
    if CertificateInvalidation.has_certificate_invalidation(user, course_key):
        return False

    return True
示例#15
0
def _listen_for_failing_grade(sender, user, course_id, grade, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a learner failing a course, mark the cert as notpassing
    if it is currently passing,
    downstream signal from COURSE_GRADE_CHANGED
    """
    cert = GeneratedCertificate.certificate_for_student(user, course_id)
    if cert is not None:
        if CertificateStatuses.is_passing_status(cert.status):
            cert.mark_notpassing(grade.percent)
            log.info(
                u'Certificate marked not passing for {user} : {course} via failing grade: {grade}'
                .format(user=user.id, course=course_id, grade=grade))
示例#16
0
def _listen_for_failing_grade(sender, user, course_id, grade, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a learner failing a course, mark the cert as notpassing
    if it is currently passing,
    downstream signal from COURSE_GRADE_CHANGED
    """
    cert = GeneratedCertificate.certificate_for_student(user, course_id)
    if cert is not None:
        if CertificateStatuses.is_passing_status(cert.status):
            cert.mark_notpassing(grade.percent)
            log.info(u'Certificate marked not passing for {user} : {course} via failing grade: {grade}'.format(
                user=user.id,
                course=course_id,
                grade=grade
            ))
示例#17
0
def _can_generate_certificate_for_status(user, course_key):
    """
    Check if the user's certificate status can handle regular (non-allowlist) certificate generation
    """
    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    if cert is None:
        return True

    if cert.status == CertificateStatuses.downloadable:
        log.info(f'Certificate with status {cert.status} already exists for {user.id} : {course_key}, and is not '
                 f'eligible for generation. Certificate cannot be generated as it is already in a final state.')
        return False

    log.info(f'Certificate with status {cert.status} already exists for {user.id} : {course_key}, and is eligible for '
             f'generation')
    return True
示例#18
0
def _generate_certificate(user, course_key):
    """
    Generate a certificate for this user, in this course run.
    """
    # Retrieve the existing certificate for the learner if it exists
    existing_certificate = GeneratedCertificate.certificate_for_student(
        user, course_key)

    profile = UserProfile.objects.get(user=user)
    profile_name = profile.name

    course = modulestore().get_course(course_key, depth=0)
    course_grade = CourseGradeFactory().read(user, course)
    enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(
        user, course_key)

    # Retain the `verify_uuid` from an existing certificate if possible, this will make it possible for the learner to
    # keep the existing URL to their certificate
    if existing_certificate and existing_certificate.verify_uuid:
        uuid = existing_certificate.verify_uuid
    else:
        uuid = uuid4().hex

    cert, created = GeneratedCertificate.objects.update_or_create(
        user=user,
        course_id=course_key,
        defaults={
            'user': user,
            'course_id': course_key,
            'mode': enrollment_mode,
            'name': profile_name,
            'status': CertificateStatuses.downloadable,
            'grade': course_grade.percent,
            'download_url': '',
            'key': '',
            'verify_uuid': uuid,
            'error_reason': ''
        })

    if created:
        created_msg = 'Certificate was created.'
    else:
        created_msg = 'Certificate already existed and was updated.'
    log.info(
        f'Generated certificate with status {cert.status} for {user.id} : {course_key}. {created_msg}'
    )
    return cert
示例#19
0
def is_certificate_invalidated(student, course_key):
    """Check whether the certificate belonging to the given student (in given course) has been invalidated.

    Arguments:
        student (user object): logged-in user
        course_key (CourseKey): The course identifier.

    Returns:
        Boolean denoting whether the certificate has been invalidated for this learner.
    """
    log.info(f"Checking if student {student.id} has an invalidated certificate in course {course_key}.")

    certificate = GeneratedCertificate.certificate_for_student(student, course_key)
    if certificate:
        return CertificateInvalidation.has_certificate_invalidation(student, course_key)

    return False
def _generate_certificate(user, course_key, status, enrollment_mode,
                          course_grade):
    """
    Generate a certificate for this user, in this course run.

    This method takes things like grade and enrollment mode as parameters because these are used to determine if the
    user is eligible for a certificate, and they're also saved in the cert itself. We want the cert to reflect the
    values that were used when determining if it was eligible for generation.
    """
    # Retrieve the existing certificate for the learner if it exists
    existing_certificate = GeneratedCertificate.certificate_for_student(
        user, course_key)

    preferred_name = get_preferred_certificate_name(user)

    # Retain the `verify_uuid` from an existing certificate if possible, this will make it possible for the learner to
    # keep the existing URL to their certificate
    if existing_certificate and existing_certificate.verify_uuid:
        uuid = existing_certificate.verify_uuid
    else:
        uuid = uuid4().hex

    cert, created = GeneratedCertificate.objects.update_or_create(
        user=user,
        course_id=course_key,
        defaults={
            'user': user,
            'course_id': course_key,
            'mode': enrollment_mode,
            'name': preferred_name,
            'status': status,
            'grade': course_grade,
            'download_url': '',
            'key': '',
            'verify_uuid': uuid,
            'error_reason': ''
        })

    if created:
        created_msg = 'Certificate was created.'
    else:
        created_msg = 'Certificate already existed and was updated.'
    log.info(
        f'Generated certificate with status {cert.status}, mode {cert.mode} and grade {cert.grade} for {user.id} '
        f': {course_key}. {created_msg}')
    return cert
示例#21
0
def fire_ungenerated_certificate_task(user, course_key, expected_verification_status=None):
    """
    Helper function to fire certificate generation task.
    Auto-generation of certificates is available for following course modes:
        1- VERIFIED
        2- CREDIT_MODE
        3- PROFESSIONAL
        4- NO_ID_PROFESSIONAL_MODE

    Certificate generation task is fired to either generate a certificate
    when there is no generated certificate for user in a particular course or
    update a certificate if it has 'unverified' status.

    Task is fired to attempt an update to a certificate
    with 'unverified' status as this method is called when a user is
    successfully verified, any certificate associated
    with such user can now be verified.

    NOTE: Purpose of restricting other course modes (HONOR and AUDIT) from auto-generation is to reduce
    traffic to workers.
    """

    allowed_enrollment_modes_list = [
        CourseMode.VERIFIED,
        CourseMode.CREDIT_MODE,
        CourseMode.PROFESSIONAL,
        CourseMode.NO_ID_PROFESSIONAL_MODE,
        CourseMode.MASTERS,
    ]
    enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(user, course_key)
    cert = GeneratedCertificate.certificate_for_student(user, course_key)

    generate_learner_certificate = (
        enrollment_mode in allowed_enrollment_modes_list and (cert is None or cert.status == 'unverified')
    )

    if generate_learner_certificate:
        kwargs = {
            'student': unicode(user.id),
            'course_key': unicode(course_key)
        }
        if expected_verification_status:
            kwargs['expected_verification_status'] = unicode(expected_verification_status)
        generate_certificate.apply_async(countdown=CERTIFICATE_DELAY_SECONDS, kwargs=kwargs)
        return True
示例#22
0
    def is_entitlement_regainable(self, entitlement):
        """
        Determines from the policy if an entitlement can still be regained by the user, if they choose
        to by leaving and regaining their entitlement within policy.regain_period days from start date of
        the course or their redemption, whichever comes later, and the expiration period hasn't passed yet
        """
        if entitlement.expired_at:
            return False

        if entitlement.enrollment_course_run:
            if GeneratedCertificate.certificate_for_student(
                    entitlement.user_id, entitlement.enrollment_course_run.course_id) is not None:
                return False

            # This is >= because a days_until_expiration 0 means that the expiration day has not fully passed yet
            # and that the entitlement should not be expired as there is still time
            return self.get_days_until_expiration(entitlement) >= 0
        return False
示例#23
0
def is_certificate_invalid(student, course_key):
    """Check that whether the student in the course has been invalidated
    for receiving certificates.

    Arguments:
        student (user object): logged-in user
        course_key (CourseKey): The course identifier.

    Returns:
        Boolean denoting whether the student in the course is invalidated
        to receive certificates
    """
    is_invalid = False
    certificate = GeneratedCertificate.certificate_for_student(student, course_key)
    if certificate is not None:
        is_invalid = CertificateInvalidation.has_certificate_invalidation(student, course_key)

    return is_invalid
示例#24
0
def is_certificate_invalid(student, course_key):
    """Check that whether the student in the course has been invalidated
    for receiving certificates.

    Arguments:
        student (user object): logged-in user
        course_key (CourseKey): The course identifier.

    Returns:
        Boolean denoting whether the student in the course is invalidated
        to receive certificates
    """
    is_invalid = False
    certificate = GeneratedCertificate.certificate_for_student(student, course_key)
    if certificate is not None:
        is_invalid = CertificateInvalidation.has_certificate_invalidation(student, course_key)

    return is_invalid
示例#25
0
def _listen_for_failing_grade(sender, user, course_id, grade, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a signal indicating that the user has failed a course run.

    If needed, mark the certificate as notpassing.
    """
    if is_on_certificate_allowlist(user, course_id):
        log.info(
            f'User {user.id} is on the allowlist for {course_id}. The failing grade will not affect the '
            f'certificate.')
        return

    cert = GeneratedCertificate.certificate_for_student(user, course_id)
    if cert is not None:
        if CertificateStatuses.is_passing_status(cert.status):
            cert.mark_notpassing(grade.percent)
            log.info(
                'Certificate marked not passing for {user} : {course} via failing grade: {grade}'
                .format(user=user.id, course=course_id, grade=grade))
示例#26
0
def _listen_for_failing_grade(sender, user, course_id, grade, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a learner failing a course, mark the cert as notpassing
    if it is currently passing,
    downstream signal from COURSE_GRADE_CHANGED
    """
    if is_using_certificate_allowlist_and_is_on_allowlist(user, course_id):
        log.info('{course_id} is using allowlist certificates, and the user {user_id} is on its allowlist. The '
                 'failing grade will not affect the certificate.'.format(course_id=course_id, user_id=user.id))
        return

    cert = GeneratedCertificate.certificate_for_student(user, course_id)
    if cert is not None:
        if CertificateStatuses.is_passing_status(cert.status):
            cert.mark_notpassing(grade.percent)
            log.info('Certificate marked not passing for {user} : {course} via failing grade: {grade}'.format(
                user=user.id,
                course=course_id,
                grade=grade
            ))
def _can_generate_certificate_for_status(user, course_key, enrollment_mode):
    """
    Check if the user's certificate status can handle regular (non-allowlist) certificate generation
    """
    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    if cert is None:
        return True

    if cert.status == CertificateStatuses.downloadable:
        if not _is_mode_now_eligible(enrollment_mode, cert):
            log.info(
                f'Certificate with status {cert.status} already exists for {user.id} : {course_key}, and is not '
                f'eligible for generation. Certificate cannot be generated as it is already in a final state. The '
                f'current enrollment mode is {enrollment_mode} and the existing cert mode is {cert.mode}'
            )
            return False

    log.info(
        f'Certificate with status {cert.status} already exists for {user.id} : {course_key}, and is eligible for '
        f'generation. The current enrollment mode is {enrollment_mode} and the existing cert mode is {cert.mode}'
    )
    return True
示例#28
0
    def test_ineligible_cert_whitelisted(self):
        """Test that audit mode students can receive a certificate if they are whitelisted."""
        # Enroll as audit
        CourseEnrollmentFactory(user=self.user_2,
                                course_id=self.course.id,
                                is_active=True,
                                mode='audit')
        # Whitelist student
        CertificateWhitelistFactory(course_id=self.course.id, user=self.user_2)

        # Generate certs
        with mock_passing_grade():
            with patch.object(XQueueInterface, 'send_to_queue') as mock_send:
                mock_send.return_value = (0, None)
                self.xqueue.add_cert(self.user_2, self.course.id)

        # Assert cert generated correctly
        self.assertTrue(mock_send.called)
        certificate = GeneratedCertificate.certificate_for_student(
            self.user_2, self.course.id)
        self.assertIsNotNone(certificate)
        self.assertEqual(certificate.mode, 'audit')
示例#29
0
    def test_ineligible_cert_whitelisted(self):
        """Test that audit mode students can receive a certificate if they are whitelisted."""
        # Enroll as audit
        CourseEnrollmentFactory(
            user=self.user_2,
            course_id=self.course.id,
            is_active=True,
            mode='audit'
        )
        # Whitelist student
        CertificateWhitelistFactory(course_id=self.course.id, user=self.user_2)

        # Generate certs
        with mock_passing_grade():
            with patch.object(XQueueInterface, 'send_to_queue') as mock_send:
                mock_send.return_value = (0, None)
                self.xqueue.add_cert(self.user_2, self.course.id)

        # Assert cert generated correctly
        self.assertTrue(mock_send.called)
        certificate = GeneratedCertificate.certificate_for_student(self.user_2, self.course.id)
        self.assertIsNotNone(certificate)
        self.assertEqual(certificate.mode, 'audit')
示例#30
0
def _listen_for_failing_grade(sender, user, course_id, grade, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a signal indicating that the user has failed a course run.

    If needed, mark the certificate as notpassing.
    """
    if is_on_certificate_allowlist(user, course_id):
        log.info(
            f'User {user.id} is on the allowlist for {course_id}. The failing grade will not affect the '
            f'certificate.')
        return

    cert = GeneratedCertificate.certificate_for_student(user, course_id)
    if cert is not None:
        if CertificateStatuses.is_passing_status(cert.status):
            enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(
                user, course_id)
            cert.mark_notpassing(mode=enrollment_mode,
                                 grade=grade.percent,
                                 source='notpassing_signal')
            log.info(
                f'Certificate marked not passing for {user.id} : {course_id} via failing grade'
            )
示例#31
0
def _set_v2_cert_status(user, course_key):
    """
    Determine the V2 certificate status for this user, in this course run.

    This is used when a downloadable cert cannot be generated, but we want to provide more info about why it cannot
    be generated.
    """
    if not _can_set_v2_cert_status(user, course_key):
        return None

    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    status = _get_cert_status_common(user, course_key, cert)
    if status is not None:
        return status

    if IDVerificationService.user_is_verified(user) and not _has_passing_grade(
            user, course_key) and cert is not None:
        if cert.status != CertificateStatuses.notpassing:
            course_grade = _get_course_grade(user, course_key)
            cert.mark_notpassing(course_grade.percent,
                                 source='certificate_generation')
        return CertificateStatuses.notpassing

    return None
示例#32
0
def get_extra_course_about_context(request, course):
    """
    Get all the extra context for the course_about page

    Arguments:
        request (Request): Request object
        course (CourseOverview): Course Overview object to add data to the context

    Returns:
        dict: Returns an empty dict if it is the testing environment otherwise returns a dict with added context
    """
    if is_testing_environment():
        return {}

    user = request.user
    course_language_names = []
    enrolled_course_group_course = None
    enroll_popup_message = cannot_enroll_message = ''

    multilingual_course = MultilingualCourse.objects.all(
    ).multilingual_course_with_course_id(course.id)
    if multilingual_course:
        course_group_courses = multilingual_course.multilingual_course_group.multilingual_courses
        course_language_codes = course_group_courses.open_multilingual_courses(
        ).language_codes_with_course_ids()
        course_language_names = get_language_names_from_codes(
            course_language_codes)

        enrolled_course_group_course = course_group_courses.all(
        ).enrolled_course(user)
        if enrolled_course_group_course:
            course_display_name = enrolled_course_group_course.course.display_name_with_default

            enroll_popup_message = Text(
                _('Warning: If you wish to change the language of this course, your progress in '
                  'the following course(s) will be erased.{line_break}{course_name}'
                  )).format(course_name=course_display_name,
                            line_break=HTML('<br>'))

    course_enrollment_count = CourseEnrollment.objects.enrollment_counts(
        course.id).get('total')

    course_requirements = course_grade = certificate = None
    if user.is_authenticated:
        course_requirements = get_pre_requisite_courses_not_completed(
            user, [course.id])
        course_grade = CourseGradeFactory().read(user, course_key=course.id)
        certificate = GeneratedCertificate.certificate_for_student(
            user, course.id)

    has_generated_cert_for_any_other_course_group_course = False
    if enrolled_course_group_course and enrolled_course_group_course.course != course:
        has_generated_cert_for_any_other_course_group_course = GeneratedCertificate.objects.filter(
            course_id=enrolled_course_group_course.course.id,
            user=user).exists()

        if has_generated_cert_for_any_other_course_group_course:
            cannot_enroll_message = _(
                'You cannot enroll in this course version as you have already earned a '
                'certificate for another version of this course!')

    context = {
        'course_languages':
        course_language_names,
        'course_requirements':
        course_requirements,
        'total_enrollments':
        course_enrollment_count,
        'self_paced':
        course.self_paced,
        'effort':
        course.effort,
        'is_course_passed':
        course_grade and getattr(course_grade, 'passed', False),
        'has_certificate':
        certificate,
        'has_user_enrolled_in_course_group_courses':
        bool(enrolled_course_group_course),
        'has_generated_cert_for_any_course_group_course':
        has_generated_cert_for_any_other_course_group_course,
        'enroll_popup_message':
        enroll_popup_message,
        'cannot_enroll_message':
        cannot_enroll_message,
    }

    return context