views.py 4.97 KB
Newer Older
1 2 3
"""URL handlers related to certificate handling by LMS"""
from dogapi import dog_stats_api
import json
4
import logging
5 6

from django.contrib.auth.models import User
7
from django.http import HttpResponse
8 9
from django.views.decorators.csrf import csrf_exempt

10
from capa.xqueue_interface import XQUEUE_METRIC_NAME
11 12 13 14
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
15
from opaque_keys.edx.locations import SlashSeparatedCourseKey
16

17
logger = logging.getLogger(__name__)
18

John Jarvis committed
19

20
@csrf_exempt
21 22 23 24 25 26 27 28 29 30 31 32 33
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():
            xqci = XQueueCertInterface()
            username = request.user.username
            student = User.objects.get(username=username)
34 35
            course_key = SlashSeparatedCourseKey.from_deprecated_string(request.POST.get('course_id'))
            course = modulestore().get_course(course_key, depth=2)
36

37
            status = certificate_status_for_student(student, course_key)['status']
38
            if status in [CertificateStatuses.unavailable, CertificateStatuses.notpassing, CertificateStatuses.error]:
39 40
                logger.info('Grading and certification requested for user {} in course {} via /request_certificate call'.format(username, course_key))
                status = xqci.add_cert(student, course_key, course=course)
41 42 43 44 45
            return HttpResponse(json.dumps({'add_status': status}), mimetype='application/json')
        return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}), mimetype='application/json')


@csrf_exempt
46 47 48 49
def update_certificate(request):
    """
    Will update GeneratedCertificate for a new certificate or
    modify an existing certificate entry.
50 51 52 53

    See models.py for a state diagram of certificate states

    This view should only ever be accessed by the xqueue server
54
    """
55

56
    status = CertificateStatuses
57
    if request.method == "POST":
58 59 60 61 62

        xqueue_body = json.loads(request.POST.get('xqueue_body'))
        xqueue_header = json.loads(request.POST.get('xqueue_header'))

        try:
63 64
            course_key = SlashSeparatedCourseKey.from_deprecated_string(xqueue_body['course_id'])

65
            cert = GeneratedCertificate.objects.get(
66 67 68
                user__username=xqueue_body['username'],
                course_id=course_key,
                key=xqueue_header['lms_key'])
69 70

        except GeneratedCertificate.DoesNotExist:
71
            logger.critical('Unable to lookup certificate\n'
72 73 74
                            'xqueue_body: {0}\n'
                            'xqueue_header: {1}'.format(
                                xqueue_body, xqueue_header))
75 76

            return HttpResponse(json.dumps({
77 78 79
                'return_code': 1,
                'content': 'unable to lookup key'}),
                mimetype='application/json')
80

81 82
        if 'error' in xqueue_body:
            cert.status = status.error
John Jarvis committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96
            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']
97
        else:
John Jarvis committed
98
            if cert.status in [status.generating, status.regenerating]:
99 100 101 102
                cert.download_uuid = xqueue_body['download_uuid']
                cert.verify_uuid = xqueue_body['verify_uuid']
                cert.download_url = xqueue_body['url']
                cert.status = status.downloadable
John Jarvis committed
103
            elif cert.status in [status.deleting]:
104 105 106
                cert.status = status.deleted
            else:
                logger.critical('Invalid state for cert update: {0}'.format(
John Jarvis committed
107
                    cert.status))
108 109
                return HttpResponse(json.dumps({
                            'return_code': 1,
John Jarvis committed
110
                            'content': 'invalid cert status'}),
111
                             mimetype='application/json')
112 113 114 115 116 117

        dog_stats_api.increment(XQUEUE_METRIC_NAME, tags=[
            u'action:update_certificate',
            u'course_id:{}'.format(cert.course_id)
        ])

118 119
        cert.save()
        return HttpResponse(json.dumps({'return_code': 0}),
120
                            mimetype='application/json')