Commit 22ed22d9 by John Jarvis Committed by Carlos Andrés Rocha

Updating the certificate app for testing

Conflicts:

	lms/djangoapps/certificates/models.py
parent d636d729
from django.utils.simplejson import dumps
from django.core.management.base import BaseCommand, CommandError
from certificates.models import GeneratedCertificate
from courseware import grades, courses
from django.contrib.auth.models import User
from django.test.client import RequestFactory
from profilehooks import profile
import cProfile
from pprint import pprint
from capa.xqueue_interface import XQueueInterface
from capa.xqueue_interface import make_xheader
from django.conf import settings
from requests.auth import HTTPBasicAuth
class Command(BaseCommand):
help = """
This command finds all GeneratedCertificate objects that do not have a
certificate generated. These come into being when a user requests a
certificate, or when grade_all_students is called (for pre-generating
certificates).
This command finds all users that have not been graded
for a single course.
It returns a json formatted list of users and their user ids
"""
# @profile
def _grade(self,student, request, course):
grades.grade(student, request, course)
def handle(self, *args, **options):
users = GeneratedCertificate.objects.filter(
download_url=None)
user_output = [{'user_id':user.user_id, 'name':user.name}
for user in users]
self.stdout.write(dumps(user_output) + "\n")
factory = RequestFactory()
course_id = 'BerkeleyX/CS169.1x/2012_Fall'
course = courses.get_course_by_id(course_id)
if settings.XQUEUE_INTERFACE.get('basic_auth') is not None:
requests_auth = HTTPBasicAuth(
*settings.XQUEUE_INTERFACE['basic_auth'])
else:
requests_auth = None
xqueue_interface = XQueueInterface(
settings.XQUEUE_INTERFACE['url'],
settings.XQUEUE_INTERFACE['django_auth'],
requests_auth,
)
header = make_xheader('/certificate', 'foo', 'test-pull')
print "Sending test message to queue"
xqueue_interface.send_to_queue(header, { 'test': 'foo' })
#enrolled_students = User.objects.filter(
# courseenrollment__course_id=course_id).prefetch_related(
# "groups").order_by('username')
#generated_certificates = GeneratedCertificate.objects.filter(
# course_id=course_id)
#request = factory.get('/')
#student = User.objects.get(username='03199618')
#print "total students: {0}".format(len(enrolled_students))
#count = 0
#for student in enrolled_students:
# count += 1
# if count % 1000 == 0:
# print "{0}/{1}".format(count, len(enrolled_students))
# grades.grade(student, request, course)
#for student in enrolled_students:
# g = grades.grade(student, request, course)
# if g['grade'] is not None:
# print str(student)
# pprint(g)
# break
from django.conf import settings as settings
from django.contrib.auth.models import User
from django.db import models
......@@ -14,131 +12,66 @@ we save these generated certificates (for later verification), we
also record the UUID so that if we regenerate the certificate it
will have the same UUID.
If certificates are being generated on the fly, a GeneratedCertificate
should be created with the user, certificate_id, and enabled set
when a student requests a certificate. When the certificate has been
generated, the download_url should be set.
Certificates are generated in batches by a cron job, when a
certificate is available for download the GeneratedCertificate
table is updated with information that will be displayed
on the course overview page.
Certificates can also be pre-generated. In this case, the user,
certificate_id, and download_url are all set before the user does
anything. When the user requests the certificate, only enabled
needs to be set to true.
'''
class GeneratedCertificate(models.Model):
user = models.ForeignKey(User, db_index=True)
# This is the name at the time of request
name = models.CharField(blank=True, max_length=255)
certificate_id = models.CharField(max_length=32, null=True, default=None)
graded_certificate_id = models.CharField(max_length=32, null=True, default=None)
download_url = models.CharField(max_length=128, null=True)
graded_download_url = models.CharField(max_length=128, null=True)
grade = models.CharField(max_length=5, null=True)
# enabled should only be true if the student has earned a grade in the course
# The student must have a grade and request a certificate for enabled to be True
enabled = models.BooleanField(default=False)
class RevokedCertificate(models.Model):
"""
This model is for when a GeneratedCertificate must be regenerated. This model
contains all the same fields, to store a record of what the GeneratedCertificate
was before it was revoked (at which time all of it's information can change when
it is regenerated).
GeneratedCertificate may be deleted once they are revoked, and then created again.
For this reason, the only link between a GeneratedCertificate and RevokedCertificate
is that they share the same user.
"""
####-------------------New Fields--------------------####
explanation = models.TextField(blank=True)
####---------Fields from GeneratedCertificate---------####
user = models.ForeignKey(User, db_index=True)
# This is the name at the time of request
name = models.CharField(blank=True, max_length=255)
certificate_id = models.CharField(max_length=32, null=True, default=None)
graded_certificate_id = models.CharField(max_length=32, null=True, default=None)
download_url = models.CharField(max_length=128, null=True)
graded_download_url = models.CharField(max_length=128, null=True)
grade = models.CharField(max_length=5, null=True)
user = models.ForeignKey(User)
course_id = models.CharField(max_length=255, default=False)
certificate_id = models.CharField(max_length=32, default=False)
graded_certificate_id = models.CharField(max_length=32, default=False)
download_url = models.CharField(max_length=128, default=False)
graded_download_url = models.CharField(max_length=128, default=False)
grade = models.CharField(max_length=5, default=False)
key = models.CharField(max_length=32, default=False)
# enabled should only be true if the student has earned a passing grade
# in the course.
enabled = models.BooleanField(default=False)
def revoke_certificate(certificate, explanation):
"""
This method takes a GeneratedCertificate. It records its information from the certificate
into a RevokedCertificate, and then marks the certificate as needing regenerating.
When the new certificiate is regenerated it will have new IDs and download URLS.
Once this method has been called, it is safe to delete the certificate, or modify the
certificate's name or grade until it has been generated again.
"""
revoked = RevokedCertificate(user=certificate.user,
name=certificate.name,
certificate_id=certificate.certificate_id,
graded_certificate_id=certificate.graded_certificate_id,
download_url=certificate.download_url,
graded_download_url=certificate.graded_download_url,
grade=certificate.grade,
enabled=certificate.enabled)
revoked.explanation = explanation
certificate.certificate_id = None
certificate.graded_certificate_id = None
certificate.download_url = None
certificate.graded_download_url = None
certificate.save()
revoked.save()
def certificate_state_for_student(student, grade):
def certificate_state_for_student(student):
'''
This returns a dictionary with a key for state, and other information. The state is one of the
following:
This returns a dictionary with a key for state, and other information.
The state is one of the following:
unavailable - A student is not eligible for a certificate.
requestable - A student is eligible to request a certificate
generating - A student has requested a certificate, but it is not generated yet.
downloadable - The certificate has been requested and is available for download.
unavailable - A student is not eligible for a certificate.
generating - A student has requested a certificate,
but it is not generated yet.
downloadable - The certificate has been requested and is
available for download.
If the state is "downloadable", the dictionary also contains "download_url" and "graded_download_url".
If the state is "downloadable", the dictionary also contains
"download_url" and "graded_download_url".
'''
if grade:
#TODO: Remove the following after debugging
if settings.DEBUG_SURVEY:
return {'state': 'requestable'}
try:
generated_certificate = GeneratedCertificate.objects.get(user=student)
if generated_certificate.enabled:
if generated_certificate.download_url:
return {'state': 'downloadable',
'download_url': generated_certificate.download_url,
'graded_download_url': generated_certificate.graded_download_url}
else:
return {'state': 'generating'}
try:
generated_certificate = GeneratedCertificate.objects.get(
user=student)
if generated_certificate.enabled:
if generated_certificate.download_url:
return {
'state': 'downloadable',
'download_url':
generated_certificate.download_url,
'graded_download_url':
generated_certificate.graded_download_url
}
else:
# If enabled=False, it may have been pre-generated but not yet requested
# Our output will be the same as if the GeneratedCertificate did not exist
pass
except GeneratedCertificate.DoesNotExist:
return {'state': 'generating'}
else:
# If enabled=False, there is no certificate available
# Our output will be the same as if the
# GeneratedCertificate did not exist
pass
return {'state': 'requestable'}
else:
# No grade, no certificate. No exceptions
return {'state': 'unavailable'}
except GeneratedCertificate.DoesNotExist:
pass
return {'state': 'unavailable'}
import json
import logging
import uuid
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.core.mail import send_mail
from django.http import Http404, HttpResponse
from django.shortcuts import redirect
import courseware.grades as grades
from certificates.models import GeneratedCertificate, certificate_state_for_student, revoke_certificate
from mitxmako.shortcuts import render_to_response, render_to_string
from student.models import UserProfile
#TODO: Finish migrating these changes from stable
# from student.survey_questions import exit_survey_list_for_student
# from student.views import student_took_survey, record_exit_survey
from certificates.models import GeneratedCertificate
from pprint import pprint
log = logging.getLogger("mitx.certificates")
@login_required
def certificate_request(request):
''' Attempt to send a certificate. '''
if not settings.END_COURSE_ENABLED:
raise Http404
def update_certificate(request):
"""
Will update GeneratedCertificate for a new certificate or
modify an existing certificate entry.
"""
if request.method == "POST":
honor_code_verify = request.POST.get('cert_request_honor_code_verify', 'false')
name_verify = request.POST.get('cert_request_name_verify', 'false')
id_verify = request.POST.get('cert_request_id_verify', 'false')
error = ''
def return_error(error):
return HttpResponse(json.dumps({'success': False,
'error': error}))
if honor_code_verify != 'true':
error += 'Please verify that you have followed the honor code to receive a certificate. '
if name_verify != 'true':
error += 'Please verify that your name is correct to receive a certificate. '
if id_verify != 'true':
error += 'Please certify that you understand the unique ID on the certificate. '
if len(error) > 0:
return return_error(error)
survey_response = record_exit_survey(request, internal_request=True)
if not survey_response['success']:
return return_error(survey_response['error'])
grade = None
student_gradesheet = grades.grade(request.user, request, course)
grade = student_gradesheet['grade']
if not grade:
return return_error('You have not earned a grade in this course. ')
generate_certificate(request.user, grade)
return HttpResponse(json.dumps({'success': True}))
else:
#This is not a POST, we should render the page with the form
student_gradesheet = grades.grade(request.user, request, course)
certificate_state = certificate_state_for_student(request.user, grade_sheet['grade'])
if certificate_state['state'] != "requestable":
return redirect("/profile")
user_info = UserProfile.objects.get(user=request.user)
took_survey = student_took_survey(user_info)
if settings.DEBUG_SURVEY:
took_survey = False
survey_list = []
if not took_survey:
survey_list = exit_survey_list_for_student(request.user)
context = {'certificate_state': certificate_state,
'took_survey': took_survey,
'survey_list': survey_list,
'name': user_info.name}
return render_to_response('cert_request.html', context)
# This method should only be called if the user has a grade and has requested a certificate
def generate_certificate(user, grade):
# Make sure to see the comments in models.GeneratedCertificate to read about the valid
# states for a GeneratedCertificate object
if grade and user.is_active:
generated_certificate = None
try:
generated_certificate = GeneratedCertificate.objects.get(user=user)
except GeneratedCertificate.DoesNotExist:
generated_certificate = GeneratedCertificate(user=user)
generated_certificate.enabled = True
if generated_certificate.graded_download_url and (generated_certificate.grade != grade):
log.critical(u"A graded certificate has been pre-generated with the grade "
"of {gen_grade} but requested by user id {userid} with grade "
"{req_grade}! The download URLs were {graded_dl_url} and "
"{ungraded_dl_url}".format(
gen_grade=generated_certificate.grade,
req_grade=grade,
graded_dl_url=generated_certificate.graded_download_url,
ungraded_dl_url=generated_certificate.download_url,
userid=user.id))
revoke_certificate(generated_certificate, "The grade on this certificate may be inaccurate.")
user_name = UserProfile.objects.get(user=user).name
if generated_certificate.download_url and (generated_certificate.name != user_name):
log.critical(u"A Certificate has been pre-generated with the name of "
"{gen_name} but current name is {user_name} (user id is "
"{userid})! The download URLs were {graded_dl_url} and "
"{ungraded_dl_url}".format(
gen_name=generated_certificate.name.encode('utf-8'),
user_name=user_name.encode('utf-8'),
graded_dl_url=generated_certificate.graded_download_url,
ungraded_dl_url=generated_certificate.download_url,
userid=user.id))
revoke_certificate(generated_certificate, "The name on this certificate may be inaccurate.")
generated_certificate.grade = grade
generated_certificate.name = user_name
generated_certificate.save()
certificate_id = generated_certificate.certificate_id
log.debug("Generating certificate for " + str(user.username) + " with ID: " + str(certificate_id))
# TODO: If the certificate was pre-generated, send the email that it is ready to download
if certificate_state_for_student(user, grade)['state'] == "downloadable":
subject = render_to_string('emails/certificate_ready_subject.txt', {})
subject = ''.join(subject.splitlines())
message = render_to_string('emails/certificate_ready.txt', {})
res = send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email, ])
else:
log.warning("Asked to generate a certificate for student " + str(user.username) + " but with a grade of " + str(grade) + " and active status " + str(user.is_active))
pprint(request)
# user = request.POST.get('user')
# try:
# generated_certificate = GeneratedCertificate.objects.get(
# key=key)
# except GeneratedCertificate.DoesNotExist:
# generated_certificate = GeneratedCertificate(user=user)
#
# enabled = request.POST.get('enabled')
# enabled = True if enabled == 'True' else False
# generated_certificate.grade = request.POST.get('grade')
# generated_certificate.download_url = request.POST.get('download_url')
# generated_certificate.graded_download_url = request.POST.get(
# 'graded_download_url')
# generated_certificate.course_id = request.POST.get('course_id')
# generated_certificate.enabled = enabled
# generated_certificate.save()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment