Пример #1
0
 def handle(self, *args, **options):
     course_id = options['course']
     log.info('Fetching ungraded students for %s.', course_id)
     ungraded = GeneratedCertificate.objects.filter(
         course_id__exact=course_id).filter(grade__exact='')
     course = courses.get_course_by_id(course_id)
     for cert in ungraded:
         if is_using_certificate_allowlist_and_is_on_allowlist(
                 cert.user, course_id):
             log.info(
                 f'{course_id} is using allowlist certificates, and the user {cert.user.id} is on its '
                 f'allowlist. Certificate will not be regraded')
         else:
             # grade the student
             grade = CourseGradeFactory().read(cert.user, course)
             log.info('grading %s - %s', cert.user, grade.percent)
             cert.grade = grade.percent
             if not options['noop']:
                 cert.save()
Пример #2
0
def request_certificate(request):
    """Request the on-demand creation of a certificate for some user, course.

    A request doesn't imply a guarantee that such a creation will take place.
    We intentionally use the same machinery as is used for doing certification
    at the end of a course run, so that we can be sure users get graded and
    then if and only if they pass, do they get a certificate issued.
    """
    if request.method == "POST":
        if request.user.is_authenticated:
            username = request.user.username
            student = User.objects.get(username=username)
            course_key = CourseKey.from_string(request.POST.get('course_id'))
            course = modulestore().get_course(course_key, depth=2)

            status = certificate_status_for_student(student,
                                                    course_key)['status']
            if is_using_certificate_allowlist_and_is_on_allowlist(
                    student, course_key):
                log.info(
                    f'{course_key} is using allowlist certificates, and the user {student.id} is on its '
                    f'allowlist. Attempt will be made to generate an allowlist certificate.'
                )
                generate_allowlist_certificate_task(student, course_key)
            elif status in [
                    CertificateStatuses.unavailable,
                    CertificateStatuses.notpassing, CertificateStatuses.error
            ]:
                log_msg = u'Grading and certification requested for user %s in course %s via /request_certificate call'
                log.info(log_msg, username, course_key)
                status = generate_user_certificates(student,
                                                    course_key,
                                                    course=course)
            return HttpResponse(json.dumps({'add_status': status}),
                                content_type='application/json')  # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps
        return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}),
                            content_type='application/json')  # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps
Пример #3
0
def update_certificate(request):
    """
    Will update GeneratedCertificate for a new certificate or
    modify an existing certificate entry.

    See models.py for a state diagram of certificate states

    This view should only ever be accessed by the xqueue server
    """

    status = CertificateStatuses
    if request.method == "POST":

        xqueue_body = json.loads(request.POST.get('xqueue_body'))
        xqueue_header = json.loads(request.POST.get('xqueue_header'))

        try:
            course_key = CourseKey.from_string(xqueue_body['course_id'])

            cert = GeneratedCertificate.eligible_certificates.get(
                user__username=xqueue_body['username'],
                course_id=course_key,
                key=xqueue_header['lms_key'])

        except GeneratedCertificate.DoesNotExist:
            log.critical(
                'Unable to lookup certificate\n'
                u'xqueue_body: %s\n'
                u'xqueue_header: %s', xqueue_body, xqueue_header)

            return HttpResponse(
                json.dumps({  # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps
                    'return_code': 1,
                    'content': 'unable to lookup key'
                }),
                content_type='application/json')

        user = cert.user
        if is_using_certificate_allowlist_and_is_on_allowlist(
                user, course_key):
            log.warning(
                f'{course_key} is using allowlist certificates, and the user {user.id} is on its allowlist. '
                f'Request to update the certificate will be ignored.')
            return HttpResponse(  # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps
                json.dumps({
                    'return_code': 1,
                    'content': 'allowlist certificate'
                }),
                content_type='application/json')

        if 'error' in xqueue_body:
            cert.status = status.error
            if 'error_reason' in xqueue_body:

                # Hopefully we will record a meaningful error
                # here if something bad happened during the
                # certificate generation process
                #
                # example:
                #  (aamorm BerkeleyX/CS169.1x/2012_Fall)
                #  <class 'simples3.bucket.S3Error'>:
                #  HTTP error (reason=error(32, 'Broken pipe'), filename=None) :
                #  certificate_agent.py:175

                cert.error_reason = xqueue_body['error_reason']
        else:
            if cert.status == status.generating:
                cert.download_uuid = xqueue_body['download_uuid']
                cert.verify_uuid = xqueue_body['verify_uuid']
                cert.download_url = xqueue_body['url']
                cert.status = status.downloadable
            elif cert.status in [status.deleting]:
                cert.status = status.deleted
            else:
                log.critical(u'Invalid state for cert update: %s', cert.status)
                return HttpResponse(  # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps
                    json.dumps({
                        'return_code': 1,
                        'content': 'invalid cert status'
                    }),
                    content_type='application/json')

        cert.save()
        return HttpResponse(
            json.dumps({'return_code': 0}),  # pylint: disable=http-response-with-content-type-json, http-response-with-json-dumps
            content_type='application/json')
Пример #4
0
def generate_students_certificates(_xmodule_instance_args, _entry_id,
                                   course_id, task_input, action_name):
    """
    For a given `course_id`, generate certificates for only students present in 'students' key in task_input
    json column, otherwise generate certificates for all enrolled students.
    """
    start_time = time()
    students_to_generate_certs_for = CourseEnrollment.objects.users_enrolled_in(
        course_id)

    student_set = task_input.get('student_set')
    if student_set == 'all_whitelisted':
        # Generate Certificates for all white listed students.
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            certificatewhitelist__course_id=course_id,
            certificatewhitelist__whitelist=True)

    elif student_set == 'whitelisted_not_generated':
        # Whitelist students who did not get certificates already.
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            certificatewhitelist__course_id=course_id,
            certificatewhitelist__whitelist=True).exclude(
                generatedcertificate__course_id=course_id,
                generatedcertificate__status__in=CertificateStatuses.
                PASSED_STATUSES)

    elif student_set == "specific_student":
        specific_student_id = task_input.get('specific_student_id')
        students_to_generate_certs_for = students_to_generate_certs_for.filter(
            id=specific_student_id)

    task_progress = TaskProgress(action_name,
                                 students_to_generate_certs_for.count(),
                                 start_time)

    current_step = {'step': 'Calculating students already have certificates'}
    task_progress.update_task_state(extra_meta=current_step)

    statuses_to_regenerate = task_input.get('statuses_to_regenerate', [])
    if student_set is not None and not statuses_to_regenerate:
        # We want to skip 'filtering students' only when students are given and statuses to regenerate are not
        students_require_certs = students_to_generate_certs_for
    else:
        students_require_certs = students_require_certificate(
            course_id, students_to_generate_certs_for, statuses_to_regenerate)

    log.info(
        f'About to attempt certificate generation for {len(students_require_certs)} users in course {course_id}. '
        f'The student_set is {student_set} and statuses_to_regenerate is {statuses_to_regenerate}'
    )
    if statuses_to_regenerate:
        # Mark existing generated certificates as 'unavailable' before regenerating
        # We need to call this method after "students_require_certificate" otherwise "students_require_certificate"
        # would return no results.
        _invalidate_generated_certificates(course_id,
                                           students_to_generate_certs_for,
                                           statuses_to_regenerate)

    task_progress.skipped = task_progress.total - len(students_require_certs)

    current_step = {'step': 'Generating Certificates'}
    task_progress.update_task_state(extra_meta=current_step)

    course = modulestore().get_course(course_id, depth=0)
    # Generate certificate for each student
    for student in students_require_certs:
        task_progress.attempted += 1
        if is_using_certificate_allowlist_and_is_on_allowlist(
                student, course_id):
            log.info(
                f'{course_id} is using allowlist certificates, and the user {student.id} is on its allowlist. '
                f'Attempt will be made to generate an allowlist certificate.')
            generate_allowlist_certificate_task(student, course_id)
        else:
            log.info(
                f'Attempt will be made to generate a certificate for user {student.id} in {course_id}.'
            )
            generate_user_certificates(student, course_id, course=course)
    return task_progress.update_task_state(extra_meta=current_step)