Commit 0f906d5a by Joe Blaylock Committed by Giulio Gratta

URL endpoint for requesting certificate generation

* API endpoint for certificate generation, a post with student id and
  course id requests that a cert be generated for that student for that
  course, using the usual grading and certificate machinery (ie, it does
  not imply whitelisting, though whitelists and blacklists will be
  respected)
* Logs each request as it comes in
* Calls xq.add_cert() and consequently, does grading synchronously on
  this app host and then queues request for certificate agent.
* This version is aware of Stanford's CME Registration hack, which
  creates a professional_designation field, used to carry titles such as
  PhD or Msc. This now gets passed in to the certification call
* example usage:
  ```
  curl --data "student_id=9999&course_id=Stanford/2013/Some_Class" http://127.0.0.1:8000/request_certificate
  ```
* TODO:
  - make grading calls into a celery task so they happen asynchronously
  - needs tests
  - needs pep8/pylint
parent e88269fd
...@@ -167,6 +167,8 @@ class XQueueCertInterface(object): ...@@ -167,6 +167,8 @@ class XQueueCertInterface(object):
if course is None: if course is None:
course = courses.get_course_by_id(course_id) course = courses.get_course_by_id(course_id)
profile = UserProfile.objects.get(user=student) profile = UserProfile.objects.get(user=student)
profile_name = profile.name
profile_title = title
# Needed # Needed
self.request.user = student self.request.user = student
...@@ -199,7 +201,7 @@ class XQueueCertInterface(object): ...@@ -199,7 +201,7 @@ class XQueueCertInterface(object):
cert.user = student cert.user = student
cert.grade = grade['percent'] cert.grade = grade['percent']
cert.course_id = course_id cert.course_id = course_id
cert.name = profile.name cert.name = profile_name
if is_whitelisted or grade['grade'] is not None: if is_whitelisted or grade['grade'] is not None:
...@@ -216,20 +218,21 @@ class XQueueCertInterface(object): ...@@ -216,20 +218,21 @@ class XQueueCertInterface(object):
key = make_hashkey(random.random()) key = make_hashkey(random.random())
cert.key = key cert.key = key
contents = { contents = {
'action': 'create', 'action': 'create',
'username': student.username, 'username': student.username,
'course_id': course_id, 'course_id': course_id,
'name': profile.name, 'name': profile_name,
'grade': grade['grade'], 'grade': grade['grade'],
'template_pdf': template_pdf, 'template_pdf': template_pdf,
'designation': profile_title,
} }
new_status = status.generating new_status = status.generating
cert.status = new_status cert.status = new_status
cert.save() cert.save()
self._send_to_xqueue(contents, key) self._send_to_xqueue(contents, key)
else: else:
new_status = status.notpassing cert_status = status.notpassing
cert.status = new_status cert.status = cert_status
cert.save() cert.save()
return new_status return new_status
......
import json
import logging import logging
from certificates.models import GeneratedCertificate
from certificates.models import CertificateStatuses as status from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse from django.http import HttpResponse
import json from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from certificates.models import certificate_status_for_student, CertificateStatuses, GeneratedCertificate
from certificates.queue import XQueueCertInterface
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.django import modulestore
use_cme = settings.FEATURES.get('USE_CME_REGISTRATION', False)
if use_cme:
from cme_registration.models import CmeUserProfile
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@csrf_exempt @csrf_exempt
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():
xq = XQueueCertInterface()
username = request.user.username
student = User.objects.get(username=username)
course_id = request.POST.get('course_id')
course = modulestore().get_instance(course_id, CourseDescriptor.id_to_location(course_id), depth=2)
title = 'None'
if use_cme:
titlelist = CmeUserProfile.objects.filter(user=student).values('professional_designation')
if len(titlelist):
print "DEBUG: {}".format(repr(titlelist))
title = titlelist[0]['professional_designation']
status = certificate_status_for_student(student, course_id)['status']
if status in [CertificateStatuses.unavailable, CertificateStatuses.notpassing, CertificateStatuses.error]:
logger.info('Grading and certification requested for user {} in course {} via /request_certificate call'.format(username, course_id))
# TODO: make xq.add_cert into async celery job w/o return so grading pushes off to util boxen
status = xq.add_cert(student, course_id, course=course, title=title)
return HttpResponse(json.dumps({'add_status': status}), mimetype='application/json')
return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}), mimetype='application/json')
@csrf_exempt
def update_certificate(request): def update_certificate(request):
""" """
Will update GeneratedCertificate for a new certificate or Will update GeneratedCertificate for a new certificate or
......
...@@ -13,6 +13,7 @@ urlpatterns = ('', # nopep8 ...@@ -13,6 +13,7 @@ urlpatterns = ('', # nopep8
# certificate view # certificate view
url(r'^update_certificate$', 'certificates.views.update_certificate'), url(r'^update_certificate$', 'certificates.views.update_certificate'),
url(r'^request_certificate$', 'certificates.views.request_certificate'),
url(r'^$', 'branding.views.index', name="root"), # Main marketing page, or redirect to courseware url(r'^$', 'branding.views.index', name="root"), # Main marketing page, or redirect to courseware
url(r'^dashboard$', 'student.views.dashboard', name="dashboard"), url(r'^dashboard$', 'student.views.dashboard', name="dashboard"),
url(r'^login$', 'student.views.signin_user', name="signin_user"), url(r'^login$', 'student.views.signin_user', name="signin_user"),
......
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