models.py 6.1 KB
Newer Older
1 2
from django.contrib.auth.models import User
from django.db import models
3
from datetime import datetime
4
from model_utils import Choices
5
from xmodule_django.models import CourseKeyField, NoneToEmptyManager
6

Victor Shnayder committed
7
"""
8 9
Certificates are created for a student and an offering of a course.

10
When a certificate is generated, a unique ID is generated so that
11
the certificate can be verified later. The ID is a UUID4, so that
John Jarvis committed
12
it can't be easily guessed and so that it is unique.
13

14 15 16 17
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.
18

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

State diagram:

[deleted,error,unavailable] [error,downloadable]
            +                +             +
            |                |             |
            |                |             |
         add_cert       regen_cert     del_cert
            |                |             |
            v                v             v
       [generating]    [regenerating]  [deleting]
            +                +             +
            |                |             |
       certificate      certificate    certificate
         created       removed,created   deleted
            +----------------+-------------+------->[error]
            |                |             |
            |                |             |
            v                v             v
      [downloadable]   [downloadable]  [deleted]

40 41 42 43 44 45 46 47 48 49 50 51 52

Eligibility:

    Students are eligible for a certificate if they pass the course
    with the following exceptions:

       If the student has allow_certificate set to False in the student profile
       he will never be issued a certificate.

       If the user and course is present in the certificate whitelist table
       then the student will be issued a certificate regardless of his grade,
       unless he has allow_certificate set to False.

Victor Shnayder committed
53
"""
John Jarvis committed
54

55

56
class CertificateStatuses(object):
57 58
    deleted      = 'deleted'
    deleting     = 'deleting'
John Jarvis committed
59
    downloadable = 'downloadable'
60 61 62 63 64 65
    error        = 'error'
    generating   = 'generating'
    notpassing   = 'notpassing'
    regenerating = 'regenerating'
    restricted   = 'restricted'
    unavailable  = 'unavailable'
John Jarvis committed
66

67
class CertificateWhitelist(models.Model):
68 69 70 71 72 73 74
    """
    Tracks students who are whitelisted, all users
    in this table will always qualify for a certificate
    regardless of their grade unless they are on the
    embargoed country restriction list
    (allow_certificate set to False in userprofile).
    """
75 76 77

    objects = NoneToEmptyManager()

78
    user = models.ForeignKey(User)
79
    course_id = CourseKeyField(max_length=255, blank=True, default=None)
80
    whitelist = models.BooleanField(default=0)
81

Calen Pennington committed
82

83
class GeneratedCertificate(models.Model):
84 85 86

    MODES = Choices('verified', 'honor', 'audit')

87
    user = models.ForeignKey(User)
88
    course_id = CourseKeyField(max_length=255, blank=True, default=None)
89 90 91 92 93 94 95
    verify_uuid = models.CharField(max_length=32, blank=True, default='')
    download_uuid = models.CharField(max_length=32, blank=True, default='')
    download_url = models.CharField(max_length=128, blank=True,  default='')
    grade = models.CharField(max_length=5, blank=True, default='')
    key = models.CharField(max_length=32, blank=True, default='')
    distinction = models.BooleanField(default=False)
    status = models.CharField(max_length=32, default='unavailable')
96
    mode = models.CharField(max_length=32, choices=MODES, default=MODES.honor)
97
    name = models.CharField(blank=True, max_length=255)
98
    created_date = models.DateTimeField(
99
        auto_now_add=True, default=datetime.now)
100
    modified_date = models.DateTimeField(
101
        auto_now=True, default=datetime.now)
John Jarvis committed
102
    error_reason = models.CharField(max_length=512, blank=True, default='')
103 104

    class Meta:
John Jarvis committed
105 106
        unique_together = (('user', 'course_id'),)

107 108 109 110 111 112 113 114 115 116 117 118
    @classmethod
    def certificate_for_student(cls, student, course_id):
        """
        This returns the certificate for a student for a particular course
        or None if no such certificate exits.
        """
        try:
            return cls.objects.get(user=student, course_id=course_id)
        except cls.DoesNotExist:
            pass

        return None
119 120

def certificate_status_for_student(student, course_id):
121
    '''
122 123
    This returns a dictionary with a key for status, and other information.
    The status is one of the following:
124

125 126 127
    unavailable  - No entry for this student--if they are actually in
                   the course, they probably have not been graded for
                   certificate generation yet.
128 129 130
    generating   - A request has been made to generate a certificate,
                   but it has not been generated yet.
    regenerating - A request has been made to regenerate a certificate,
John Jarvis committed
131
                   but it has not been generated yet.
132
    deleting     - A request has been made to delete a certificate.
John Jarvis committed
133

134 135
    deleted      - The certificate has been deleted.
    downloadable - The certificate is available for download.
136
    notpassing   - The student was graded but is not passing
137
    restricted   - The student is on the restricted embargo list and
138 139 140
                   should not be issued a certificate. This will
                   be set if allow_certificate is set to False in
                   the userprofile table
141 142 143

    If the status is "downloadable", the dictionary also contains
    "download_url".
144

145
    If the student has been graded, the dictionary also contains their
146
    grade for the course with the key "grade".
147
    '''
148

149 150
    try:
        generated_certificate = GeneratedCertificate.objects.get(
151 152 153
            user=student, course_id=course_id)
        d = {'status': generated_certificate.status,
             'mode': generated_certificate.mode}
154 155
        if generated_certificate.grade:
            d['grade'] = generated_certificate.grade
156
        if generated_certificate.status == CertificateStatuses.downloadable:
157
            d['download_url'] = generated_certificate.download_url
158 159

        return d
160 161
    except GeneratedCertificate.DoesNotExist:
        pass
162
    return {'status': CertificateStatuses.unavailable, 'mode': GeneratedCertificate.MODES.honor}