from django.contrib.auth.models import User from django.db import models from datetime import datetime """ Certificates are created for a student and an offering of a course. When a certificate is generated, a unique ID is generated so that the certificate can be verified later. The ID is a UUID4, so that it can't be easily guessed and so that it is unique. 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. 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] 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. """ class CertificateStatuses(object): unavailable = 'unavailable' generating = 'generating' regenerating = 'regenerating' deleting = 'deleting' deleted = 'deleted' downloadable = 'downloadable' notpassing = 'notpassing' restricted = 'restricted' error = 'error' class CertificateWhitelist(models.Model): """ 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). """ user = models.ForeignKey(User) course_id = models.CharField(max_length=255, blank=True, default='') whitelist = models.BooleanField(default=0) class GeneratedCertificate(models.Model): user = models.ForeignKey(User) course_id = models.CharField(max_length=255, blank=True, default='') 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') name = models.CharField(blank=True, max_length=255) created_date = models.DateTimeField( auto_now_add=True, default=datetime.now) modified_date = models.DateTimeField( auto_now=True, default=datetime.now) error_reason = models.CharField(max_length=512, blank=True, default='') class Meta: unique_together = (('user', 'course_id'),) def certificate_status_for_student(student, course_id): ''' This returns a dictionary with a key for status, and other information. The status is one of the following: unavailable - No entry for this student--if they are actually in the course, they probably have not been graded for certificate generation yet. 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, but it has not been generated yet. deleting - A request has been made to delete a certificate. deleted - The certificate has been deleted. downloadable - The certificate is available for download. notpassing - The student was graded but is not passing restricted - The student is on the restricted embargo list and should not be issued a certificate. This will be set if allow_certificate is set to False in the userprofile table If the status is "downloadable", the dictionary also contains "download_url". If the student has been graded, the dictionary also contains their grade for the course with the key "grade". ''' try: generated_certificate = GeneratedCertificate.objects.get( user=student, course_id=course_id) d = {'status': generated_certificate.status} if generated_certificate.grade: d['grade'] = generated_certificate.grade if generated_certificate.status == CertificateStatuses.downloadable: d['download_url'] = generated_certificate.download_url return d except GeneratedCertificate.DoesNotExist: pass return {'status': CertificateStatuses.unavailable}