Commit 779480ba by Diana Huang

Merge pull request #3889 from edx/diana/fix-gen-cert

Fix gen_cert_report to use CourseKeys.
parents 797a1643 019374a4
from django.core.management.base import BaseCommand
"""
Generate a report of certificate statuses
"""
from django.core.management.base import BaseCommand, CommandError
from certificates.models import GeneratedCertificate
from django.contrib.auth.models import User
from optparse import make_option
from django.conf import settings
from opaque_keys import InvalidKeyError
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.keys import CourseKey
from xmodule.modulestore.locations import SlashSeparatedCourseKey
from xmodule.modulestore.django import modulestore
from django.db.models import Count
......@@ -12,7 +19,7 @@ class Command(BaseCommand):
help = """
Generate a certificate status report for all courses that have ended.
Generate a certificate status report for a given course.
This command does not do anything other than report the current
certificate status.
......@@ -34,81 +41,89 @@ class Command(BaseCommand):
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 = modulestore().get_course(course_id)
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']]
try:
course_id = CourseKey.from_string(options['course'])
except InvalidKeyError:
print("Course id {} could not be parsed as a CourseKey; falling back to SSCK.from_dep_str".format(options['course']))
course_id = SlashSeparatedCourseKey.from_deprecated_string(options['course'])
else:
ended_courses = self._ended_courses()
raise CommandError("You must specify a course")
cert_data = {}
for course_id in ended_courses:
# find students who are active
# enrolled students are always downloable + notpassing
print "Looking up certificate states for {0}".format(course_id)
enrolled_current = User.objects.filter(
courseenrollment__course_id=course_id,
courseenrollment__is_active=True)
enrolled_total = User.objects.filter(
courseenrollment__course_id=course_id)
verified_enrolled = GeneratedCertificate.objects.filter(
course_id__exact=course_id, mode__exact='verified')
honor_enrolled = GeneratedCertificate.objects.filter(
course_id__exact=course_id, mode__exact='honor')
audit_enrolled = GeneratedCertificate.objects.filter(
course_id__exact=course_id, mode__exact='audit')
cert_data[course_id] = {'enrolled_current': enrolled_current.count(),
'enrolled_total': enrolled_total.count(),
'verified_enrolled': verified_enrolled.count(),
'honor_enrolled': honor_enrolled.count(),
'audit_enrolled': audit_enrolled.count()}
status_tally = GeneratedCertificate.objects.filter(
course_id__exact=course_id).values('status').annotate(
dcount=Count('status'))
cert_data[course_id].update(
{status['status']: status['dcount']
for status in status_tally})
mode_tally = GeneratedCertificate.objects.filter(
course_id__exact=course_id,
status__exact='downloadable').values('mode').annotate(
dcount=Count('mode'))
cert_data[course_id].update(
{mode['mode']: mode['dcount']
for mode in mode_tally})
# find students who are active
# number of enrolled students = downloadable + notpassing
print "Looking up certificate states for {0}".format(options['course'])
enrolled_current = User.objects.filter(
courseenrollment__course_id=course_id,
courseenrollment__is_active=True
)
enrolled_total = User.objects.filter(
courseenrollment__course_id=course_id
)
verified_enrolled = GeneratedCertificate.objects.filter(
course_id__exact=course_id, mode__exact='verified'
)
honor_enrolled = GeneratedCertificate.objects.filter(
course_id__exact=course_id, mode__exact='honor'
)
audit_enrolled = GeneratedCertificate.objects.filter(
course_id__exact=course_id, mode__exact='audit'
)
cert_data[course_id] = {
'enrolled_current': enrolled_current.count(),
'enrolled_total': enrolled_total.count(),
'verified_enrolled': verified_enrolled.count(),
'honor_enrolled': honor_enrolled.count(),
'audit_enrolled': audit_enrolled.count()
}
status_tally = GeneratedCertificate.objects.filter(
course_id__exact=course_id
).values('status').annotate(
dcount=Count('status')
)
cert_data[course_id].update(
{status['status']: status['dcount']
for status in status_tally})
mode_tally = GeneratedCertificate.objects.filter(
course_id__exact=course_id,
status__exact='downloadable'
).values('mode').annotate(
dcount=Count('mode')
)
cert_data[course_id].update(
{mode['mode']: mode['dcount']
for mode in mode_tally}
)
# all states we have seen far all courses
status_headings = sorted(set(
[status for course in cert_data
for status in cert_data[course]]))
for status in cert_data[course]])
)
# print the heading for the report
print "{:>26}".format("course ID"),
print ' '.join(["{:>16}".format(heading)
for heading in status_headings])
for heading in status_headings]
)
# print the report
for course_id in cert_data:
print "{0:>26}".format(course_id[0:24]),
for heading in status_headings:
if heading in cert_data[course_id]:
print "{:>16}".format(cert_data[course_id][heading]),
else:
print " " * 16,
print
print "{0:>26}".format(course_id.to_deprecated_string()),
for heading in status_headings:
if heading in cert_data[course_id]:
print "{:>16}".format(cert_data[course_id][heading]),
else:
print " " * 16,
print
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