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