예제 #1
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 can_generate_certificate_task(student, course_key):
                log.info(
                    f'{course_key} is using V2 course certificates. Attempt will be made to generate a V2 '
                    f'certificate for user {student.id}.')
                generate_certificate_task(student, course_key)
            elif status in [
                    CertificateStatuses.unavailable,
                    CertificateStatuses.notpassing, CertificateStatuses.error
            ]:
                log_msg = '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
예제 #2
0
def regenerate_certificate_for_user(request):
    """
    Regenerate certificates for a user.

    This is meant to be used by support staff through the UI in lms/djangoapps/support

    Arguments:
        request (HttpRequest): The request object

    Returns:
        HttpResponse

    Example Usage:

        POST /certificates/regenerate
            * username: "******"
            * course_key: "edX/DemoX/Demo_Course"

        Response: 200 OK

    """
    # Check the POST parameters, returning a 400 response if they're not valid.
    params, response = _validate_post_params(request.POST)
    if response is not None:
        return response

    user = params["user"]
    course_key = params["course_key"]

    course_overview = get_course_overview_or_none(course_key)
    if not course_overview:
        msg = _("The course {course_key} does not exist").format(
            course_key=course_key)
        return HttpResponseBadRequest(msg)

    # Check that the user is enrolled in the course
    if not CourseEnrollment.is_enrolled(user, course_key):
        msg = _("User {user_id} is not enrolled in the course {course_key}"
                ).format(user_id=user.id, course_key=course_key)
        return HttpResponseBadRequest(msg)

    # Attempt to regenerate certificates
    try:
        generate_certificate_task(user, course_key)
    except:  # pylint: disable=bare-except
        # We are pessimistic about the kinds of errors that might get thrown by the
        # certificates API.  This may be overkill, but we're logging everything so we can
        # track down unexpected errors.
        log.exception(
            f"Could not regenerate certificate for user {user.id} in course {course_key}"
        )
        return HttpResponseServerError(
            _("An unexpected error occurred while regenerating certificates."))

    log.info(
        f"Started regenerating certificates for user {user.id} in course {course_key} from the support page."
    )
    return HttpResponse(200)
예제 #3
0
    def test_generation(self):
        """
        Test that a cert is successfully generated
        """
        cert = get_certificate_for_user_id(self.user.id, self.course_run_key)
        assert not cert

        with mock.patch(PASSING_GRADE_METHOD, return_value=True):
            with mock.patch(ID_VERIFIED_METHOD, return_value=True):
                generate_certificate_task(self.user, self.course_run_key)

                cert = get_certificate_for_user_id(self.user.id, self.course_run_key)
                assert cert.status == CertificateStatuses.downloadable
                assert cert.mode == CourseMode.VERIFIED
예제 #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_allowlisted':
        # Generate Certificates for all allowlisted students.
        students_to_generate_certs_for = get_enrolled_allowlisted_users(course_id)

    elif student_set == 'allowlisted_not_generated':
        # Allowlisted students who did not yet receive certificates
        students_to_generate_certs_for = get_enrolled_allowlisted_not_passing_users(course_id)

    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}')

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

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

    # Generate certificate for each student
    for student in students_require_certs:
        task_progress.attempted += 1
        log.info(f'Attempt will be made to generate a course certificate for {student.id} : {course_id}.')
        generate_certificate_task(student, course_id)
    return task_progress.update_task_state(extra_meta=current_step)
예제 #5
0
    def test_generation_notpassing(self):
        """
        Test that a cert is successfully generated with a status of notpassing
        """
        GeneratedCertificateFactory(user=self.user,
                                    course_id=self.course_run_key,
                                    status=CertificateStatuses.unavailable,
                                    mode=CourseMode.AUDIT)

        with mock.patch(PASSING_GRADE_METHOD, return_value=False):
            with mock.patch(ID_VERIFIED_METHOD, return_value=True):
                generate_certificate_task(self.user, self.course_run_key)

                cert = get_certificate_for_user_id(self.user.id,
                                                   self.course_run_key)
                assert cert.status == CertificateStatuses.notpassing
                assert cert.mode == CourseMode.VERIFIED
예제 #6
0
    def test_generation_unverified(self, enable_idv_requirement):
        """
        Test that a cert is successfully generated with a status of unverified
        """
        cert = get_certificate_for_user_id(self.user.id, self.course_run_key)
        assert not cert

        with mock.patch(PASSING_GRADE_METHOD, return_value=True):
            with mock.patch(ID_VERIFIED_METHOD, return_value=False):
                with mock.patch.dict(settings.FEATURES, ENABLE_CERTIFICATES_IDV_REQUIREMENT=enable_idv_requirement):
                    generate_certificate_task(self.user, self.course_run_key)

                    cert = get_certificate_for_user_id(self.user.id, self.course_run_key)
                    assert cert.mode == CourseMode.VERIFIED
                    if enable_idv_requirement:
                        assert cert.status == CertificateStatuses.unverified
                    else:
                        assert cert.status == CertificateStatuses.downloadable
예제 #7
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 can_generate_certificate_task(student, course_id):
            log.info(
                f'{course_id} is using V2 certificates. Attempt will be made to generate a V2 certificate '
                f'for user {student.id}.')
            generate_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)