Merge pull request #1047 from MITx/feature/jarv/cert-commands
Django commands for certificates
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from certificates.models import certificate_status_for_student
|
||||
from certificates.queue import XQueueCertInterface
|
||||
from django.contrib.auth.models import User
|
||||
from student.models import UserProfile
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
help = """
|
||||
Looks for names that have unicode characters
|
||||
and queues them up for a certificate request
|
||||
"""
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# TODO this is only temporary for CS169 certs
|
||||
|
||||
course_id = 'BerkeleyX/CS169.1x/2012_Fall'
|
||||
|
||||
enrolled_students = User.objects.filter(
|
||||
courseenrollment__course_id=course_id).prefetch_related(
|
||||
"groups").order_by('username')
|
||||
xq = XQueueCertInterface()
|
||||
print "Looking for unusual names.."
|
||||
for student in enrolled_students:
|
||||
if certificate_status_for_student(
|
||||
student, course_id)['status'] == 'unavailable':
|
||||
continue
|
||||
name = UserProfile.objects.get(user=student).name
|
||||
for c in name:
|
||||
if ord(c) >= 0x200:
|
||||
ret = xq.add_cert(student, course_id)
|
||||
if ret == 'generating':
|
||||
print 'generating for {0}'.format(student)
|
||||
break
|
||||
@@ -0,0 +1,97 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from certificates.models import GeneratedCertificate
|
||||
from django.contrib.auth.models import User
|
||||
from optparse import make_option
|
||||
from django.conf import settings
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from django.db.models import Count
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
help = """
|
||||
|
||||
Generate a certificate status report for all courses that have ended.
|
||||
This command does not do anything other than report the current
|
||||
certificate status.
|
||||
|
||||
unavailable - A student is not eligible for a certificate.
|
||||
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
|
||||
|
||||
"""
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('-c', '--course',
|
||||
metavar='COURSE_ID',
|
||||
dest='course',
|
||||
default=None,
|
||||
help='Only generate for COURSE_ID'),
|
||||
)
|
||||
|
||||
def _ended_courses(self):
|
||||
for course_id in [course # all courses in COURSE_LISTINGS
|
||||
for sub in settings.COURSE_LISTINGS
|
||||
for course in settings.COURSE_LISTINGS[sub]]:
|
||||
course_loc = CourseDescriptor.id_to_location(course_id)
|
||||
course = modulestore().get_instance(course_id, course_loc)
|
||||
if course.has_ended():
|
||||
yield course_id
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# Find all courses that have ended
|
||||
|
||||
if options['course']:
|
||||
ended_courses = [options['course']]
|
||||
else:
|
||||
ended_courses = self._ended_courses()
|
||||
|
||||
cert_data = {}
|
||||
|
||||
for course_id in ended_courses:
|
||||
|
||||
# find students who are enrolled
|
||||
print "Looking up certificate states for {0}".format(course_id)
|
||||
enrolled_students = User.objects.filter(
|
||||
courseenrollment__course_id=course_id).prefetch_related(
|
||||
"groups").order_by('username')
|
||||
unavailable_count = enrolled_students.count() - \
|
||||
GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id).count()
|
||||
cert_data[course_id] = {'enrolled': enrolled_students.count()}
|
||||
cert_data[course_id].update({'unavailable': unavailable_count})
|
||||
|
||||
tallies = GeneratedCertificate.objects.values(
|
||||
'status').annotate(dcount=Count('status'))
|
||||
cert_data[course_id].update(
|
||||
{status['status']: status['dcount']
|
||||
for status in tallies})
|
||||
|
||||
# all states we have seen far all courses
|
||||
status_headings = set(
|
||||
[status for course in cert_data
|
||||
for status in cert_data[course]])
|
||||
|
||||
# print the heading for the report
|
||||
print "{:>20}".format("course ID"),
|
||||
print ' '.join(["{:>12}".format(heading)
|
||||
for heading in status_headings])
|
||||
|
||||
# print the report
|
||||
for course_id in cert_data:
|
||||
print "{0:>20}".format(course_id[0:18]),
|
||||
for heading in status_headings:
|
||||
if heading in cert_data[course_id]:
|
||||
print "{:>12}".format(cert_data[course_id][heading]),
|
||||
else:
|
||||
print " " * 12,
|
||||
print
|
||||
@@ -2,29 +2,92 @@ from django.core.management.base import BaseCommand
|
||||
from certificates.models import certificate_status_for_student
|
||||
from certificates.queue import XQueueCertInterface
|
||||
from django.contrib.auth.models import User
|
||||
from optparse import make_option
|
||||
from django.conf import settings
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from certificates.models import CertificateStatuses
|
||||
import datetime
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
||||
help = """
|
||||
Find all students that have need certificates
|
||||
and put certificate requests on the queue
|
||||
Find all students that need certificates
|
||||
for courses that have finished and
|
||||
put their cert requests on the queue
|
||||
|
||||
This is only for BerkeleyX/CS169.1x/2012_Fall
|
||||
Use the --noop option to test without actually
|
||||
putting certificates on the queue to be generated.
|
||||
"""
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('-n', '--noop',
|
||||
action='store_true',
|
||||
dest='noop',
|
||||
default=False,
|
||||
help="Don't add certificate requests to the queue"),
|
||||
make_option('-c', '--course',
|
||||
metavar='COURSE_ID',
|
||||
dest='course',
|
||||
default=False,
|
||||
help='Grade and generate certificates for a specific course'),
|
||||
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# TODO This is only temporary for CS169 certs
|
||||
# Will only generate a certificate if the current
|
||||
# status is in this state
|
||||
|
||||
course_id = 'BerkeleyX/CS169.1x/2012_Fall'
|
||||
enrolled_students = User.objects.filter(
|
||||
courseenrollment__course_id=course_id).prefetch_related(
|
||||
"groups").order_by('username')
|
||||
xq = XQueueCertInterface()
|
||||
for student in enrolled_students:
|
||||
if certificate_status_for_student(
|
||||
student, course_id)['status'] == 'unavailable':
|
||||
ret = xq.add_cert(student, course_id)
|
||||
if ret == 'generating':
|
||||
print 'generating for {0}'.format(student)
|
||||
VALID_STATUSES = [
|
||||
CertificateStatuses.unavailable
|
||||
]
|
||||
|
||||
# Print update after this many students
|
||||
|
||||
STATUS_INTERVAL = 500
|
||||
|
||||
if options['course']:
|
||||
ended_courses = [options['course']]
|
||||
else:
|
||||
# Find all courses that have ended
|
||||
ended_courses = []
|
||||
for course_id in [course # all courses in COURSE_LISTINGS
|
||||
for sub in settings.COURSE_LISTINGS
|
||||
for course in settings.COURSE_LISTINGS[sub]]:
|
||||
course_loc = CourseDescriptor.id_to_location(course_id)
|
||||
course = modulestore().get_instance(course_id, course_loc)
|
||||
if course.has_ended():
|
||||
ended_courses.append(course_id)
|
||||
|
||||
for course_id in ended_courses:
|
||||
print "Fetching enrolled students for {0}".format(course_id)
|
||||
enrolled_students = User.objects.filter(
|
||||
courseenrollment__course_id=course_id).prefetch_related(
|
||||
"groups").order_by('username')
|
||||
xq = XQueueCertInterface()
|
||||
total = enrolled_students.count()
|
||||
count = 0
|
||||
start = datetime.datetime.now()
|
||||
for student in enrolled_students:
|
||||
count += 1
|
||||
if count % STATUS_INTERVAL == 0:
|
||||
# Print a status update with an approximation of
|
||||
# how much time is left based on how long the last
|
||||
# interval took
|
||||
diff = datetime.datetime.now() - start
|
||||
timeleft = diff * (total - count) / STATUS_INTERVAL
|
||||
hours, remainder = divmod(timeleft.seconds, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
print "{0}/{1} completed ~{2:02}:{3:02}m remaining".format(
|
||||
count, total, hours, minutes)
|
||||
start = datetime.datetime.now()
|
||||
|
||||
if certificate_status_for_student(
|
||||
student, course_id)['status'] in VALID_STATUSES:
|
||||
if not options['noop']:
|
||||
# Add the certificate request to the queue
|
||||
ret = xq.add_cert(student, course_id)
|
||||
if ret == 'generating':
|
||||
print '{0} - {1}'.format(student, ret)
|
||||
|
||||
Reference in New Issue
Block a user