예제 #1
0
def _listen_for_id_verification_status_changed(sender, user, **kwargs):  # pylint: disable=unused-argument
    """
    Catches a track change signal, determines user status,
    calls _fire_ungenerated_certificate_task for passing grades
    """
    if not auto_certificate_generation_enabled():
        return

    user_enrollments = CourseEnrollment.enrollments_for_user(user=user)

    grade_factory = CourseGradeFactory()
    expected_verification_status = IDVerificationService.user_status(user)
    expected_verification_status = expected_verification_status['status']
    for enrollment in user_enrollments:
        if is_using_certificate_allowlist_and_is_on_allowlist(
                user, enrollment.course_id):
            log.info(
                f'{enrollment.course_id} is using allowlist certificates, and the user {user.id} is on its '
                f'allowlist. Attempt will be made to generate an allowlist certificate. Id verification status '
                f'is {expected_verification_status}')
            generate_allowlist_certificate_task(user, enrollment.course_id)
        elif grade_factory.read(user=user,
                                course=enrollment.course_overview).passed:
            if _fire_ungenerated_certificate_task(
                    user, enrollment.course_id, expected_verification_status):
                message = (
                    u'Certificate generation task initiated for {user} : {course} via track change '
                    + u'with verification status of {status}')
                log.info(
                    message.format(user=user.id,
                                   course=enrollment.course_id,
                                   status=expected_verification_status))
예제 #2
0
    def handle(self, *args, **options):
        # database args will override cmd line args
        if options['args_from_database']:
            options = self.get_args_from_database()

        # Since we're optionally using database args we can't simply make users required in the arguments
        if not options["user"]:
            raise CommandError("You must specify a list of users")

        course_key = options['course_key']
        if not course_key:
            raise CommandError("You must specify a course-key")

        # Parse the serialized course key into a CourseKey
        try:
            course_key = CourseKey.from_string(course_key)
        except InvalidKeyError as e:
            raise CommandError("You must specify a valid course-key") from e

        # Loop over each user, and ask that a cert be generated for them
        users_str = options['user']
        for user_id in users_str:
            user = None
            try:
                user = User.objects.get(id=user_id)
            except User.DoesNotExist:
                log.warning('User {user} could not be found'.format(user=user_id))
            if user is not None:
                log.info(
                    'Calling generate_allowlist_certificate_task for {user} : {course}'.format(
                        user=user.id,
                        course=course_key
                    ))
                generate_allowlist_certificate_task(user, course_key)
예제 #3
0
def _listen_for_enrollment_mode_change(sender, user, course_key, mode,
                                       **kwargs):  # pylint: disable=unused-argument
    """
    Listen for the signal indicating that a user's enrollment mode has changed.

    If possible, grant the user a course certificate. Note that we intentionally do not revoke certificates here, even
    if the user has moved to the audit track.
    """
    if modes_api.is_eligible_for_certificate(mode):
        if is_using_certificate_allowlist_and_is_on_allowlist(
                user, course_key):
            log.info(
                f'{course_key} is using allowlist certificates, and the user {user.id} is on its allowlist. '
                f'Attempt will be made to generate an allowlist certificate since the enrollment mode is now '
                f'{mode}.')
            generate_allowlist_certificate_task(user, course_key)
예제 #4
0
 def test_handle_valid(self):
     """
     Test handling of a valid user/course run combo
     """
     assert _can_generate_allowlist_certificate(self.user,
                                                self.course_run_key)
     assert generate_allowlist_certificate_task(self.user,
                                                self.course_run_key)
 def test_handle_invalid(self):
     """
     Test handling of an invalid user/course run combo
     """
     self.assertFalse(
         can_generate_allowlist_certificate(self.user, self.course_run_key))
     self.assertFalse(
         generate_allowlist_certificate_task(self.user,
                                             self.course_run_key))
    def test_handle_invalid(self):
        """
        Test handling of an invalid user/course run combo
        """
        u = UserFactory()

        assert not _can_generate_allowlist_certificate(u, self.course_run_key)
        assert not generate_allowlist_certificate_task(u, self.course_run_key)
        assert not generate_certificate_task(u, self.course_run_key)
        assert _set_allowlist_cert_status(u, self.course_run_key) is None
    def handle(self, *args, **options):
        # Parse the serialized course key into a CourseKey
        course_key = options['course_key']
        if not course_key:
            raise CommandError("You must specify a course-key")

        try:
            course_key = CourseKey.from_string(course_key)
        except InvalidKeyError as e:
            raise CommandError("You must specify a valid course-key") from e

        # Loop over each user, and ask that a cert be generated for them
        users_str = options['user']
        for user_identifier in users_str:
            user = _get_user_from_identifier(user_identifier)
            if user is not None:
                log.info(
                    'Calling generate_allowlist_certificate_task for {user} : {course}'
                    .format(user=user.id, course=course_key))
                generate_allowlist_certificate_task(user, course_key)
예제 #8
0
def _listen_for_certificate_allowlist_append(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a user being added to or modified on the allowlist
    """
    if not auto_certificate_generation_enabled():
        return

    if is_on_certificate_allowlist(instance.user, instance.course_id):
        log.info(
            f'User {instance.user.id} is now on the allowlist for course {instance.course_id}. Attempt will be '
            f'made to generate an allowlist certificate.')
        return generate_allowlist_certificate_task(instance.user,
                                                   instance.course_id)
예제 #9
0
def _listen_for_certificate_whitelist_append(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a user being added to or modified on the whitelist (allowlist)
    """
    if not auto_certificate_generation_enabled():
        return

    if is_using_certificate_allowlist_and_is_on_allowlist(instance.user, instance.course_id):
        log.info(f'{instance.course_id} is using allowlist certificates, and the user {instance.user.id} is now on '
                 f'its allowlist. Attempt will be made to generate an allowlist certificate.')
        return generate_allowlist_certificate_task(instance.user, instance.course_id)

    if _fire_ungenerated_certificate_task(instance.user, instance.course_id):
        log.info('Certificate generation task initiated for {user} : {course} via whitelist'.format(
            user=instance.user.id,
            course=instance.course_id
        ))
예제 #10
0
    def test_generate_allowlist_certificate_fail(self):
        """
        Test stop certificate process by raising a filter exception when the user is in the
        allow list.

        Expected result:
            - CertificateCreationRequested is triggered and executes TestStopCertificateGenerationStep.
            - The certificate is not generated.
        """
        CertificateAllowlistFactory.create(course_id=self.course_run.id, user=self.user)

        certificate_generated = generate_allowlist_certificate_task(self.user, self.course_run.id)

        self.assertFalse(certificate_generated)
        self.assertFalse(
            GeneratedCertificate.objects.filter(
                user=self.user, course_id=self.course_run.id, mode=CourseMode.HONOR,
            )
        )
예제 #11
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
    """
    if is_using_certificate_allowlist_and_is_on_allowlist(user, course_id):
        log.info(
            f'{course_id} is using allowlist certificates, and the user {user.id} is on its allowlist. Attempt '
            f'will be made to generate an allowlist certificate as a passing grade was received.'
        )
        return generate_allowlist_certificate_task(user, course_id)

    if not auto_certificate_generation_enabled():
        return

    if _fire_ungenerated_certificate_task(user, course_id):
        log.info(
            u'Certificate generation task initiated for {user} : {course} via passing grade'
            .format(user=user.id, course=course_id))
예제 #12
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))

    if is_using_certificate_allowlist_and_is_on_allowlist(user, course_key):
        log.info(
            '{course} is using allowlist certificates, and the user {user} is on its allowlist. Attempt will be '
            'made to generate an allowlist certificate.'.format(
                course=course_key, user=user.id))
        generate_allowlist_certificate_task(user, course_key)
        return True

    log.info(
        '{course} is not using allowlist certificates (or user {user} is not on its allowlist). The normal '
        'generation logic will be followed.'.format(course=course_key,
                                                    user=user.id))

    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