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 patch('courseware.grades.grade',
                   Mock(return_value={
                       'grade': 'Pass',
                       'percent': 0.75
                   })):
            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')
Beispiel #2
0
    def refundable(self):
        """
        For paid/verified certificates, students may receive a refund if they have
        a verified certificate and the deadline for refunds has not yet passed.
        """
        # In order to support manual refunds past the deadline, set can_refund on this object.
        # On unenrolling, the "unenroll_done" signal calls CertificateItem.refund_cert_callback(),
        # which calls this method to determine whether to refund the order.
        # This can't be set directly because refunds currently happen as a side-effect of unenrolling.
        # (side-effects are bad)
        if getattr(self, 'can_refund', None) is not None:
            return True

        # If the student has already been given a certificate they should not be refunded
        if GeneratedCertificate.certificate_for_student(
                self.user, self.course_id) is not None:
            return False

        #TODO - When Course administrators to define a refund period for paid courses then refundable will be supported. # pylint: disable=W0511

        course_mode = CourseMode.mode_for_course(self.course_id, 'verified')
        if course_mode is None:
            return False
        else:
            return True
Beispiel #3
0
def fire_ungenerated_certificate_task(user, course_id):
    """
    Helper function to fire un-generated certificate tasks
    """
    if GeneratedCertificate.certificate_for_student(user, course_id) is None:
        generate_certificate.apply_async(student=user, course_key=course_id)
        return True
Beispiel #4
0
def fire_ungenerated_certificate_task(user,
                                      course_key,
                                      expected_verification_status=None):
    """
    Helper function to fire un-generated certificate tasks

    The 'mode_is_verified' query is copied from the GeneratedCertificate model,
    but is done here in an attempt to reduce traffic to the workers.
    If the learner is verified and their cert has the 'unverified' status,
    we regenerate the cert.
    """
    enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(
        user, course_key)
    mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    if mode_is_verified and (cert is None or cert.status == 'unverified'):
        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
Beispiel #5
0
def _listen_for_passing_grade(sender, user, course_id, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a learner passing a course, send cert generation task,
    downstream signal from COURSE_GRADE_CHANGED
    """

    # No flags enabled
    if (
        not waffle.waffle().is_enabled(waffle.SELF_PACED_ONLY) and
        not waffle.waffle().is_enabled(waffle.INSTRUCTOR_PACED_ONLY)
    ):
        return

    # Only SELF_PACED_ONLY flag enabled
    if waffle.waffle().is_enabled(waffle.SELF_PACED_ONLY):
        if not courses.get_course_by_id(course_key, depth=0).self_paced:
            return

    # Only INSTRUCTOR_PACED_ONLY flag enabled
    elif waffle.waffle().is_enabled(waffle.INSTRUCTOR_PACED_ONLY):
        if courses.get_course_by_id(course_key, depth=0).self_paced:
            return
    if GeneratedCertificate.certificate_for_student(self.user, self.course_id) is None:
        generate_certificate.apply_async(
            student=user,
            course_key=course_id,
        )
        log.info(u'Certificate generation task initiated for {user} : {course} via passing grade'.format(
            user=user.id,
            course=course_id
        ))
Beispiel #6
0
def fire_ungenerated_certificate_task(user, course_key):
    """
    Helper function to fire un-generated certificate tasks
    :param user: A User object.
    :param course_id: A CourseKey object.
    """
    if GeneratedCertificate.certificate_for_student(user, course_key) is None:
        generate_certificate.apply_async(kwargs={
            'student': unicode(user.id),
            'course_key': unicode(course_key),
        })
        return True
Beispiel #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.
    """

    allowed_enrollment_modes_list = [
        CourseMode.VERIFIED,
        CourseMode.CREDIT_MODE,
        CourseMode.PROFESSIONAL,
        CourseMode.NO_ID_PROFESSIONAL_MODE,
    ]
    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
Beispiel #8
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.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
Beispiel #9
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.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
Beispiel #10
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
Beispiel #11
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
Beispiel #12
0
def fire_ungenerated_certificate_task(user, course_key):
    """
    Helper function to fire un-generated certificate tasks

    The 'mode_is_verified' query is copied from the GeneratedCertificate model,
    but is done here in an attempt to reduce traffic to the workers.
    If the learner is verified and their cert has the 'unverified' status,
    we regenerate the cert.
    """
    enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(user, course_key)
    mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
    cert = GeneratedCertificate.certificate_for_student(user, course_key)
    if mode_is_verified and (cert is None or cert.status == 'unverified'):
        generate_certificate.apply_async(kwargs={
            'student': unicode(user.id),
            'course_key': unicode(course_key),
        })
        return True
Beispiel #13
0
    def refundable(self):
        """
        For paid/verified certificates, students may receive a refund if they have
        a verified certificate and the deadline for refunds has not yet passed.
        """
        # In order to support manual refunds past the deadline, set can_refund on this object.
        # On unenrolling, the "unenroll_done" signal calls CertificateItem.refund_cert_callback(),
        # which calls this method to determine whether to refund the order.
        # This can't be set directly because refunds currently happen as a side-effect of unenrolling.
        # (side-effects are bad)
        if getattr(self, 'can_refund', None) is not None:
            return True

        # If the student has already been given a certificate they should not be refunded
        if GeneratedCertificate.certificate_for_student(self.user, self.course_id) is not None:
            return False

        course_mode = CourseMode.mode_for_course(self.course_id, 'verified')
        if course_mode is None:
            return False
        else:
            return True
    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 patch('courseware.grades.grade', Mock(return_value={'grade': 'Pass', 'percent': 0.75})):
            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')