Revert "Disable audit certificates for new audit enrollments."
This reverts commit 60860e3aa8.
This commit is contained in:
@@ -20,7 +20,6 @@ from student.models import UserProfile, CourseEnrollment
|
||||
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
|
||||
|
||||
from certificates.models import (
|
||||
CertificateStatuses,
|
||||
GeneratedCertificate,
|
||||
certificate_status_for_student,
|
||||
CertificateStatuses as status,
|
||||
@@ -121,14 +120,14 @@ class XQueueCertInterface(object):
|
||||
Change the certificate status to unavailable (if it exists) and request
|
||||
grading. Passing grades will put a certificate request on the queue.
|
||||
|
||||
Return the certificate.
|
||||
Return the status object.
|
||||
"""
|
||||
# TODO: when del_cert is implemented and plumbed through certificates
|
||||
# repo also, do a deletion followed by a creation r/t a simple
|
||||
# recreation. XXX: this leaves orphan cert files laying around in
|
||||
# AWS. See note in the docstring too.
|
||||
try:
|
||||
certificate = GeneratedCertificate.eligible_certificates.get(user=student, course_id=course_id)
|
||||
certificate = GeneratedCertificate.objects.get(user=student, course_id=course_id)
|
||||
|
||||
LOGGER.info(
|
||||
(
|
||||
@@ -184,7 +183,8 @@ class XQueueCertInterface(object):
|
||||
raise NotImplementedError
|
||||
|
||||
# pylint: disable=too-many-statements
|
||||
def add_cert(self, student, course_id, course=None, forced_grade=None, template_file=None, generate_pdf=True):
|
||||
def add_cert(self, student, course_id, course=None, forced_grade=None, template_file=None,
|
||||
title='None', generate_pdf=True):
|
||||
"""
|
||||
Request a new certificate for a student.
|
||||
|
||||
@@ -211,7 +211,7 @@ class XQueueCertInterface(object):
|
||||
If a student does not have a passing grade the status
|
||||
will change to status.notpassing
|
||||
|
||||
Returns the newly created certificate instance
|
||||
Returns the student's status and newly created certificate instance
|
||||
"""
|
||||
|
||||
valid_statuses = [
|
||||
@@ -225,6 +225,7 @@ class XQueueCertInterface(object):
|
||||
]
|
||||
|
||||
cert_status = certificate_status_for_student(student, course_id)['status']
|
||||
new_status = cert_status
|
||||
cert = None
|
||||
|
||||
if cert_status not in valid_statuses:
|
||||
@@ -239,98 +240,155 @@ class XQueueCertInterface(object):
|
||||
cert_status,
|
||||
unicode(valid_statuses)
|
||||
)
|
||||
return None
|
||||
|
||||
# The caller can optionally pass a course in to avoid
|
||||
# re-fetching it from Mongo. If they have not provided one,
|
||||
# get it from the modulestore.
|
||||
if course is None:
|
||||
course = modulestore().get_course(course_id, depth=0)
|
||||
|
||||
profile = UserProfile.objects.get(user=student)
|
||||
profile_name = profile.name
|
||||
|
||||
# Needed for access control in grading.
|
||||
self.request.user = student
|
||||
self.request.session = {}
|
||||
|
||||
is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
|
||||
grade = grades.grade(student, self.request, course)
|
||||
enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
|
||||
mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
|
||||
user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
|
||||
cert_mode = enrollment_mode
|
||||
is_eligible_for_certificate = is_whitelisted or CourseMode.is_eligible_for_certificate(enrollment_mode)
|
||||
|
||||
# For credit mode generate verified certificate
|
||||
if cert_mode == CourseMode.CREDIT_MODE:
|
||||
cert_mode = CourseMode.VERIFIED
|
||||
|
||||
if template_file is not None:
|
||||
template_pdf = template_file
|
||||
elif mode_is_verified and user_is_verified:
|
||||
template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(id=course_id)
|
||||
elif mode_is_verified and not user_is_verified:
|
||||
template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
|
||||
cert_mode = GeneratedCertificate.MODES.honor
|
||||
else:
|
||||
# honor code and audit students
|
||||
template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
|
||||
if forced_grade:
|
||||
grade['grade'] = forced_grade
|
||||
# grade the student
|
||||
|
||||
cert, __ = GeneratedCertificate.eligible_certificates.get_or_create(user=student, course_id=course_id)
|
||||
# re-use the course passed in optionally so we don't have to re-fetch everything
|
||||
# for every student
|
||||
if course is None:
|
||||
course = modulestore().get_course(course_id, depth=0)
|
||||
profile = UserProfile.objects.get(user=student)
|
||||
profile_name = profile.name
|
||||
|
||||
cert.mode = cert_mode
|
||||
cert.user = student
|
||||
cert.grade = grade['percent']
|
||||
cert.course_id = course_id
|
||||
cert.name = profile_name
|
||||
cert.download_url = ''
|
||||
# Needed
|
||||
self.request.user = student
|
||||
self.request.session = {}
|
||||
|
||||
# If this user's enrollment is not eligible to receive a
|
||||
# certificate, mark it as such for reporting and
|
||||
# analytics.
|
||||
if not is_eligible_for_certificate:
|
||||
cert.eligible_for_certificate = False
|
||||
cert.status = CertificateStatuses.auditing
|
||||
cert.save()
|
||||
LOGGER.info(
|
||||
u"Student %s with enrollment mode %s is not eligible for a certificate.",
|
||||
student.id,
|
||||
enrollment_mode
|
||||
)
|
||||
return cert
|
||||
course_name = course.display_name or unicode(course_id)
|
||||
is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
|
||||
grade = grades.grade(student, self.request, course)
|
||||
enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
|
||||
mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
|
||||
user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
|
||||
cert_mode = enrollment_mode
|
||||
|
||||
# Strip HTML from grade range label
|
||||
grade_contents = grade.get('grade', None)
|
||||
try:
|
||||
grade_contents = lxml.html.fromstring(grade_contents).text_content()
|
||||
except (TypeError, XMLSyntaxError, ParserError) as exc:
|
||||
LOGGER.info(
|
||||
(
|
||||
u"Could not retrieve grade for student %s "
|
||||
u"in the course '%s' "
|
||||
u"because an exception occurred while parsing the "
|
||||
u"grade contents '%s' as HTML. "
|
||||
u"The exception was: '%s'"
|
||||
),
|
||||
student.id,
|
||||
unicode(course_id),
|
||||
grade_contents,
|
||||
unicode(exc)
|
||||
)
|
||||
# For credit mode generate verified certificate
|
||||
if cert_mode == CourseMode.CREDIT_MODE:
|
||||
cert_mode = CourseMode.VERIFIED
|
||||
|
||||
# Log if the student is whitelisted
|
||||
if is_whitelisted:
|
||||
LOGGER.info(
|
||||
u"Student %s is whitelisted in '%s'",
|
||||
student.id,
|
||||
unicode(course_id)
|
||||
)
|
||||
# If they are not, short-circuit and don't generate cert
|
||||
if mode_is_verified and user_is_verified:
|
||||
template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(id=course_id)
|
||||
elif mode_is_verified and not user_is_verified:
|
||||
template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
|
||||
cert_mode = GeneratedCertificate.MODES.honor
|
||||
else:
|
||||
cert.status = status.notpassing
|
||||
# honor code and audit students
|
||||
template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
|
||||
if forced_grade:
|
||||
grade['grade'] = forced_grade
|
||||
|
||||
cert, __ = GeneratedCertificate.objects.get_or_create(user=student, course_id=course_id)
|
||||
|
||||
cert.mode = cert_mode
|
||||
cert.user = student
|
||||
cert.grade = grade['percent']
|
||||
cert.course_id = course_id
|
||||
cert.name = profile_name
|
||||
cert.download_url = ''
|
||||
# Strip HTML from grade range label
|
||||
grade_contents = grade.get('grade', None)
|
||||
try:
|
||||
grade_contents = lxml.html.fromstring(grade_contents).text_content()
|
||||
except (TypeError, XMLSyntaxError, ParserError) as exc:
|
||||
LOGGER.info(
|
||||
(
|
||||
u"Could not retrieve grade for student %s "
|
||||
u"in the course '%s' "
|
||||
u"because an exception occurred while parsing the "
|
||||
u"grade contents '%s' as HTML. "
|
||||
u"The exception was: '%s'"
|
||||
),
|
||||
student.id,
|
||||
unicode(course_id),
|
||||
grade_contents,
|
||||
unicode(exc)
|
||||
)
|
||||
|
||||
# Despite blowing up the xml parser, bad values here are fine
|
||||
grade_contents = None
|
||||
|
||||
if is_whitelisted or grade_contents is not None:
|
||||
|
||||
if is_whitelisted:
|
||||
LOGGER.info(
|
||||
u"Student %s is whitelisted in '%s'",
|
||||
student.id,
|
||||
unicode(course_id)
|
||||
)
|
||||
|
||||
# check to see whether the student is on the
|
||||
# the embargoed country restricted list
|
||||
# otherwise, put a new certificate request
|
||||
# on the queue
|
||||
|
||||
if self.restricted.filter(user=student).exists():
|
||||
new_status = status.restricted
|
||||
cert.status = new_status
|
||||
cert.save()
|
||||
|
||||
LOGGER.info(
|
||||
(
|
||||
u"Student %s is in the embargoed country restricted "
|
||||
u"list, so their certificate status has been set to '%s' "
|
||||
u"for the course '%s'. "
|
||||
u"No certificate generation task was sent to the XQueue."
|
||||
),
|
||||
student.id,
|
||||
new_status,
|
||||
unicode(course_id)
|
||||
)
|
||||
else:
|
||||
key = make_hashkey(random.random())
|
||||
cert.key = key
|
||||
contents = {
|
||||
'action': 'create',
|
||||
'username': student.username,
|
||||
'course_id': unicode(course_id),
|
||||
'course_name': course_name,
|
||||
'name': profile_name,
|
||||
'grade': grade_contents,
|
||||
'template_pdf': template_pdf,
|
||||
}
|
||||
if template_file:
|
||||
contents['template_pdf'] = template_file
|
||||
if generate_pdf:
|
||||
new_status = status.generating
|
||||
else:
|
||||
new_status = status.downloadable
|
||||
cert.verify_uuid = uuid4().hex
|
||||
|
||||
cert.status = new_status
|
||||
cert.save()
|
||||
|
||||
if generate_pdf:
|
||||
try:
|
||||
self._send_to_xqueue(contents, key)
|
||||
except XQueueAddToQueueError as exc:
|
||||
new_status = ExampleCertificate.STATUS_ERROR
|
||||
cert.status = new_status
|
||||
cert.error_reason = unicode(exc)
|
||||
cert.save()
|
||||
LOGGER.critical(
|
||||
(
|
||||
u"Could not add certificate task to XQueue. "
|
||||
u"The course was '%s' and the student was '%s'."
|
||||
u"The certificate task status has been marked as 'error' "
|
||||
u"and can be re-submitted with a management command."
|
||||
), course_id, student.id
|
||||
)
|
||||
else:
|
||||
LOGGER.info(
|
||||
(
|
||||
u"The certificate status has been set to '%s'. "
|
||||
u"Sent a certificate grading task to the XQueue "
|
||||
u"with the key '%s'. "
|
||||
),
|
||||
new_status,
|
||||
key
|
||||
)
|
||||
else:
|
||||
new_status = status.notpassing
|
||||
cert.status = new_status
|
||||
cert.save()
|
||||
|
||||
LOGGER.info(
|
||||
@@ -341,85 +399,10 @@ class XQueueCertInterface(object):
|
||||
),
|
||||
student.id,
|
||||
unicode(course_id),
|
||||
cert.status
|
||||
new_status
|
||||
)
|
||||
return cert
|
||||
|
||||
# Check to see whether the student is on the the embargoed
|
||||
# country restricted list. If so, they should not receive a
|
||||
# certificate -- set their status to restricted and log it.
|
||||
if self.restricted.filter(user=student).exists():
|
||||
cert.status = status.restricted
|
||||
cert.save()
|
||||
|
||||
LOGGER.info(
|
||||
(
|
||||
u"Student %s is in the embargoed country restricted "
|
||||
u"list, so their certificate status has been set to '%s' "
|
||||
u"for the course '%s'. "
|
||||
u"No certificate generation task was sent to the XQueue."
|
||||
),
|
||||
student.id,
|
||||
cert.status,
|
||||
unicode(course_id)
|
||||
)
|
||||
return cert
|
||||
|
||||
# Finally, generate the certificate and send it off.
|
||||
return self._generate_cert(cert, course, student, grade_contents, template_pdf, generate_pdf)
|
||||
|
||||
def _generate_cert(self, cert, course, student, grade_contents, template_pdf, generate_pdf):
|
||||
"""
|
||||
Generate a certificate for the student. If `generate_pdf` is True,
|
||||
sends a request to XQueue.
|
||||
"""
|
||||
course_id = unicode(course.id)
|
||||
|
||||
key = make_hashkey(random.random())
|
||||
cert.key = key
|
||||
contents = {
|
||||
'action': 'create',
|
||||
'username': student.username,
|
||||
'course_id': course_id,
|
||||
'course_name': course.display_name or course_id,
|
||||
'name': cert.name,
|
||||
'grade': grade_contents,
|
||||
'template_pdf': template_pdf,
|
||||
}
|
||||
if generate_pdf:
|
||||
cert.status = status.generating
|
||||
else:
|
||||
cert.status = status.downloadable
|
||||
cert.verify_uuid = uuid4().hex
|
||||
|
||||
cert.save()
|
||||
|
||||
if generate_pdf:
|
||||
try:
|
||||
self._send_to_xqueue(contents, key)
|
||||
except XQueueAddToQueueError as exc:
|
||||
cert.status = ExampleCertificate.STATUS_ERROR
|
||||
cert.error_reason = unicode(exc)
|
||||
cert.save()
|
||||
LOGGER.critical(
|
||||
(
|
||||
u"Could not add certificate task to XQueue. "
|
||||
u"The course was '%s' and the student was '%s'."
|
||||
u"The certificate task status has been marked as 'error' "
|
||||
u"and can be re-submitted with a management command."
|
||||
), course_id, student.id
|
||||
)
|
||||
else:
|
||||
LOGGER.info(
|
||||
(
|
||||
u"The certificate status has been set to '%s'. "
|
||||
u"Sent a certificate grading task to the XQueue "
|
||||
u"with the key '%s'. "
|
||||
),
|
||||
cert.status,
|
||||
key
|
||||
)
|
||||
return cert
|
||||
return new_status, cert
|
||||
|
||||
def add_example_cert(self, example_cert):
|
||||
"""Add a task to create an example certificate.
|
||||
|
||||
Reference in New Issue
Block a user