Example #1
0
def get_grade_book_page(request, course, course_key):
    """
    Get student records per page along with page information i.e current page, total pages and
    offset information.
    """
    # Unsanitized offset
    current_offset = request.GET.get('offset', 0)
    enrolled_students = User.objects.filter(
        courseenrollment__course_id=course_key,
        courseenrollment__is_active=1).order_by('username').select_related(
            "profile")

    total_students = enrolled_students.count()
    page = calculate_page_info(current_offset, total_students)
    offset = page["offset"]
    total_pages = page["total_pages"]

    if total_pages > 1:
        # Apply limit on queryset only if total number of students are greater then MAX_STUDENTS_PER_PAGE_GRADE_BOOK.
        enrolled_students = enrolled_students[offset:offset +
                                              MAX_STUDENTS_PER_PAGE_GRADE_BOOK]

    with modulestore().bulk_operations(course.location.course_key):
        student_info = [{
            'username': student.username,
            'id': student.id,
            'email': student.email,
            'grade_summary': course_grades.summary(student, course)
        } for student in enrolled_students]
    return student_info, page
Example #2
0
def get_grade_book_page(request, course, course_key):
    """
    Get student records per page along with page information i.e current page, total pages and
    offset information.
    """
    # Unsanitized offset
    current_offset = request.GET.get('offset', 0)
    enrolled_students = User.objects.filter(
        courseenrollment__course_id=course_key,
        courseenrollment__is_active=1
    ).order_by('username').select_related("profile")

    total_students = enrolled_students.count()
    page = calculate_page_info(current_offset, total_students)
    offset = page["offset"]
    total_pages = page["total_pages"]

    if total_pages > 1:
        # Apply limit on queryset only if total number of students are greater then MAX_STUDENTS_PER_PAGE_GRADE_BOOK.
        enrolled_students = enrolled_students[offset: offset + MAX_STUDENTS_PER_PAGE_GRADE_BOOK]

    with modulestore().bulk_operations(course.location.course_key):
        student_info = [
            {
                'username': student.username,
                'id': student.id,
                'email': student.email,
                'grade_summary': course_grades.summary(student, course)
            }
            for student in enrolled_students
        ]
    return student_info, page
def student_grades(student, request, course, use_offline=False):  # pylint: disable=unused-argument
    '''
    This is the main interface to get grades.  It has the same parameters as grades.grade, as well
    as use_offline.  If use_offline is True then this will look for an offline computed gradeset in the DB.
    '''
    if not use_offline:
        return course_grades.summary(student, course)

    try:
        ocg = models.OfflineComputedGrade.objects.get(user=student, course_id=course.id)
    except models.OfflineComputedGrade.DoesNotExist:
        return dict(
            raw_scores=[],
            section_breakdown=[],
            msg='Error: no offline gradeset available for {}, {}'.format(student, course.id)
        )

    gradeset = json.loads(ocg.gradeset)
    # Convert score dicts back to Score tuples:

    def score_from_dict(encoded):
        """ Given a formerly JSON-encoded Score tuple, return the Score tuple """
        if encoded['module_id']:
            encoded['module_id'] = UsageKey.from_string(encoded['module_id'])
        return Score(**encoded)

    totaled_scores = gradeset['totaled_scores']
    for section in totaled_scores:
        totaled_scores[section] = [score_from_dict(score) for score in totaled_scores[section]]
    gradeset['raw_scores'] = [score_from_dict(score) for score in gradeset['raw_scores']]
    return gradeset
    def get_grade_summary(self):
        """
        calls course_grades.summary for current user and course.

        the keywords for the returned object are
        - grade : A final letter grade.
        - percent : The final percent for the class (rounded up).
        - section_breakdown : A breakdown of each section that makes
            up the grade. (For display)
        - grade_breakdown : A breakdown of the major components that
            make up the final grade. (For display)
        """
        return course_grades.summary(self.student_user, self.course)
    def get_grade_summary(self):
        """
        calls course_grades.summary for current user and course.

        the keywords for the returned object are
        - grade : A final letter grade.
        - percent : The final percent for the class (rounded up).
        - section_breakdown : A breakdown of each section that makes
            up the grade. (For display)
        - grade_breakdown : A breakdown of the major components that
            make up the final grade. (For display)
        """
        return course_grades.summary(self.student_user, self.course)
def offline_grade_calculation(course_key):
    '''
    Compute grades for all students for a specified course, and save results to the DB.
    '''

    tstart = time.time()
    enrolled_students = User.objects.filter(
        courseenrollment__course_id=course_key,
        courseenrollment__is_active=1).prefetch_related("groups").order_by(
            'username')

    enc = MyEncoder()

    print "{} enrolled students".format(len(enrolled_students))
    course = get_course_by_id(course_key)

    for student in enrolled_students:
        request = DummyRequest()
        request.user = student
        request.session = {}

        gradeset = course_grades.summary(student, course, keep_raw_scores=True)
        # Convert Score namedtuples to dicts:
        totaled_scores = gradeset['totaled_scores']
        for section in totaled_scores:
            totaled_scores[section] = [
                score._asdict() for score in totaled_scores[section]
            ]
        gradeset['raw_scores'] = [
            score._asdict() for score in gradeset['raw_scores']
        ]
        # Encode as JSON and save:
        gradeset_str = enc.encode(gradeset)
        ocg, _created = models.OfflineComputedGrade.objects.get_or_create(
            user=student, course_id=course_key)
        ocg.gradeset = gradeset_str
        ocg.save()
        print "%s done" % student  # print statement used because this is run by a management command

    tend = time.time()
    dt = tend - tstart

    ocgl = models.OfflineComputedGradeLog(course_id=course_key,
                                          seconds=dt,
                                          nstudents=len(enrolled_students))
    ocgl.save()
    print ocgl
    print "All Done!"
Example #7
0
    def handle(self, *args, **options):
        course_id = options['course']
        print "Fetching ungraded students for {0}".format(course_id)
        ungraded = GeneratedCertificate.objects.filter(  # pylint: disable=no-member
            course_id__exact=course_id).filter(grade__exact='')
        course = courses.get_course_by_id(course_id)
        factory = RequestFactory()
        request = factory.get('/')

        for cert in ungraded:
            # grade the student
            grade = course_grades.summary(cert.user, course)
            print "grading {0} - {1}".format(cert.user, grade['percent'])
            cert.grade = grade['percent']
            if not options['noop']:
                cert.save()
    def handle(self, *args, **options):
        course_id = options['course']
        print "Fetching ungraded students for {0}".format(course_id)
        ungraded = GeneratedCertificate.objects.filter(  # pylint: disable=no-member
            course_id__exact=course_id
        ).filter(grade__exact='')
        course = courses.get_course_by_id(course_id)
        factory = RequestFactory()
        request = factory.get('/')

        for cert in ungraded:
            # grade the student
            grade = course_grades.summary(cert.user, course)
            print "grading {0} - {1}".format(cert.user, grade['percent'])
            cert.grade = grade['percent']
            if not options['noop']:
                cert.save()
def student_grades(student,
                   request,
                   course,
                   keep_raw_scores=False,
                   use_offline=False):
    '''
    This is the main interface to get grades.  It has the same parameters as grades.grade, as well
    as use_offline.  If use_offline is True then this will look for an offline computed gradeset in the DB.
    '''
    if not use_offline:
        return course_grades.summary(student,
                                     course,
                                     keep_raw_scores=keep_raw_scores)

    try:
        ocg = models.OfflineComputedGrade.objects.get(user=student,
                                                      course_id=course.id)
    except models.OfflineComputedGrade.DoesNotExist:
        return dict(
            raw_scores=[],
            section_breakdown=[],
            msg='Error: no offline gradeset available for {}, {}'.format(
                student, course.id))

    gradeset = json.loads(ocg.gradeset)

    # Convert score dicts back to Score tuples:

    def score_from_dict(encoded):
        """ Given a formerly JSON-encoded Score tuple, return the Score tuple """
        if encoded['module_id']:
            encoded['module_id'] = UsageKey.from_string(encoded['module_id'])
        return Score(**encoded)

    totaled_scores = gradeset['totaled_scores']
    for section in totaled_scores:
        totaled_scores[section] = [
            score_from_dict(score) for score in totaled_scores[section]
        ]
    gradeset['raw_scores'] = [
        score_from_dict(score) for score in gradeset['raw_scores']
    ]
    return gradeset
def offline_grade_calculation(course_key):
    '''
    Compute grades for all students for a specified course, and save results to the DB.
    '''

    tstart = time.time()
    enrolled_students = User.objects.filter(
        courseenrollment__course_id=course_key,
        courseenrollment__is_active=1
    ).prefetch_related("groups").order_by('username')

    enc = MyEncoder()

    print "{} enrolled students".format(len(enrolled_students))
    course = get_course_by_id(course_key)

    for student in enrolled_students:
        request = DummyRequest()
        request.user = student
        request.session = {}

        gradeset = course_grades.summary(student, course)
        # Convert Score namedtuples to dicts:
        totaled_scores = gradeset['totaled_scores']
        for section in totaled_scores:
            totaled_scores[section] = [score._asdict() for score in totaled_scores[section]]
        gradeset['raw_scores'] = [score._asdict() for score in gradeset['raw_scores']]
        # Encode as JSON and save:
        gradeset_str = enc.encode(gradeset)
        ocg, _created = models.OfflineComputedGrade.objects.get_or_create(user=student, course_id=course_key)
        ocg.gradeset = gradeset_str
        ocg.save()
        print "%s done" % student  	# print statement used because this is run by a management command

    tend = time.time()
    dt = tend - tstart

    ocgl = models.OfflineComputedGradeLog(course_id=course_key, seconds=dt, nstudents=len(enrolled_students))
    ocgl.save()
    print ocgl
    print "All Done!"
Example #11
0
    def add_cert(self,
                 student,
                 course_id,
                 course=None,
                 forced_grade=None,
                 template_file=None,
                 generate_pdf=True):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.
          generate_pdf - Boolean should a message be sent in queue to generate certificate PDF

        Will change the certificate status to 'generating' or
        `downloadable` in case of web view certificates.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the newly created certificate instance
        """

        valid_statuses = [
            status.generating,
            status.unavailable,
            status.deleted,
            status.error,
            status.notpassing,
            status.downloadable,
            status.auditing,
            status.audit_passing,
            status.audit_notpassing,
        ]

        cert_status = certificate_status_for_student(student,
                                                     course_id)['status']
        cert = None

        if cert_status not in valid_statuses:
            LOGGER.warning(
                (u"Cannot create certificate generation task for user %s "
                 u"in the course '%s'; "
                 u"the certificate status '%s' is not one of %s."), student.id,
                unicode(course_id), cert_status, unicode(valid_statuses))
            return None

        # The caller can optionally pass a course in to avoid
        # re-fetching it from Mongo. If they have not provided one,
        # get it from the modulestore.
        if course is None:
            course = modulestore().get_course(course_id, depth=0)

        profile = UserProfile.objects.get(user=student)
        profile_name = profile.name

        # Needed for access control in grading.
        self.request.user = student
        self.request.session = {}

        is_whitelisted = self.whitelist.filter(user=student,
                                               course_id=course_id,
                                               whitelist=True).exists()
        grade = course_grades.summary(student, course)
        enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(
            student, course_id)
        mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
        user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(
            student)
        cert_mode = enrollment_mode
        is_eligible_for_certificate = is_whitelisted or CourseMode.is_eligible_for_certificate(
            enrollment_mode)
        unverified = False
        # For credit mode generate verified certificate
        if cert_mode == CourseMode.CREDIT_MODE:
            cert_mode = CourseMode.VERIFIED

        if template_file is not None:
            template_pdf = template_file
        elif mode_is_verified and user_is_verified:
            template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(
                id=course_id)
        elif mode_is_verified and not user_is_verified:
            template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(
                id=course_id)
            if CourseMode.mode_for_course(course_id, CourseMode.HONOR):
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                unverified = True
        else:
            # honor code and audit students
            template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(
                id=course_id)
        if forced_grade:
            grade['grade'] = forced_grade

        LOGGER.info((
            u"Certificate generated for student %s in the course: %s with template: %s. "
            u"given template: %s, "
            u"user is verified: %s, "
            u"mode is verified: %s"), student.username, unicode(course_id),
                    template_pdf, template_file, user_is_verified,
                    mode_is_verified)

        cert, created = GeneratedCertificate.objects.get_or_create(
            user=student, course_id=course_id)  # pylint: disable=no-member

        cert.mode = cert_mode
        cert.user = student
        cert.grade = grade['percent']
        cert.course_id = course_id
        cert.name = profile_name
        cert.download_url = ''

        # Strip HTML from grade range label
        grade_contents = grade.get('grade', None)
        try:
            grade_contents = lxml.html.fromstring(
                grade_contents).text_content()
            passing = True
        except (TypeError, XMLSyntaxError, ParserError) as exc:
            LOGGER.info((u"Could not retrieve grade for student %s "
                         u"in the course '%s' "
                         u"because an exception occurred while parsing the "
                         u"grade contents '%s' as HTML. "
                         u"The exception was: '%s'"), student.id,
                        unicode(course_id), grade_contents, unicode(exc))

            # Log if the student is whitelisted
            if is_whitelisted:
                LOGGER.info(u"Student %s is whitelisted in '%s'", student.id,
                            unicode(course_id))
                passing = True
            else:
                passing = False

        # If this user's enrollment is not eligible to receive a
        # certificate, mark it as such for reporting and
        # analytics. Only do this if the certificate is new, or
        # already marked as ineligible -- we don't want to mark
        # existing audit certs as ineligible.
        cutoff = settings.AUDIT_CERT_CUTOFF_DATE
        if (cutoff and cert.created_date >= cutoff
            ) and not is_eligible_for_certificate:
            cert.status = CertificateStatuses.audit_passing if passing else CertificateStatuses.audit_notpassing
            cert.save()
            LOGGER.info(
                u"Student %s with enrollment mode %s is not eligible for a certificate.",
                student.id, enrollment_mode)
            return cert
        # If they are not passing, short-circuit and don't generate cert
        elif not passing:
            cert.status = status.notpassing
            cert.save()

            LOGGER.info(
                (u"Student %s does not have a grade for '%s', "
                 u"so their certificate status has been set to '%s'. "
                 u"No certificate generation task was sent to the XQueue."),
                student.id, unicode(course_id), cert.status)
            return cert

        # Check to see whether the student is on the the embargoed
        # country restricted list. If so, they should not receive a
        # certificate -- set their status to restricted and log it.
        if self.restricted.filter(user=student).exists():
            cert.status = status.restricted
            cert.save()

            LOGGER.info(
                (u"Student %s is in the embargoed country restricted "
                 u"list, so their certificate status has been set to '%s' "
                 u"for the course '%s'. "
                 u"No certificate generation task was sent to the XQueue."),
                student.id, cert.status, unicode(course_id))
            return cert

        if unverified:
            cert.status = status.unverified
            cert.save()
            LOGGER.info(
                (u"User %s has a verified enrollment in course %s "
                 u"but is missing ID verification. "
                 u"Certificate status has been set to unverified"),
                student.id,
                unicode(course_id),
            )
            return cert

        # Finally, generate the certificate and send it off.
        return self._generate_cert(cert, course, student, grade_contents,
                                   template_pdf, generate_pdf)
Example #12
0
    def add_cert(self, student, course_id, course=None, forced_grade=None, template_file=None, generate_pdf=True):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.
          generate_pdf - Boolean should a message be sent in queue to generate certificate PDF

        Will change the certificate status to 'generating' or
        `downloadable` in case of web view certificates.

        The course must not be a CCX.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the newly created certificate instance
        """

        if hasattr(course_id, "ccx"):
            LOGGER.warning(
                (
                    u"Cannot create certificate generation task for user %s "
                    u"in the course '%s'; "
                    u"certificates are not allowed for CCX courses."
                ),
                student.id,
                unicode(course_id),
            )
            return None

        valid_statuses = [
            status.generating,
            status.unavailable,
            status.deleted,
            status.error,
            status.notpassing,
            status.downloadable,
            status.auditing,
            status.audit_passing,
            status.audit_notpassing,
        ]

        cert_status = certificate_status_for_student(student, course_id)["status"]
        cert = None

        if cert_status not in valid_statuses:
            LOGGER.warning(
                (
                    u"Cannot create certificate generation task for user %s "
                    u"in the course '%s'; "
                    u"the certificate status '%s' is not one of %s."
                ),
                student.id,
                unicode(course_id),
                cert_status,
                unicode(valid_statuses),
            )
            return None

        # The caller can optionally pass a course in to avoid
        # re-fetching it from Mongo. If they have not provided one,
        # get it from the modulestore.
        if course is None:
            course = modulestore().get_course(course_id, depth=0)

        profile = UserProfile.objects.get(user=student)
        profile_name = profile.name

        # Needed for access control in grading.
        self.request.user = student
        self.request.session = {}

        is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
        grade = course_grades.summary(student, course)
        enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
        mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
        user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
        cert_mode = enrollment_mode
        is_eligible_for_certificate = is_whitelisted or CourseMode.is_eligible_for_certificate(enrollment_mode)
        unverified = False
        # For credit mode generate verified certificate
        if cert_mode == CourseMode.CREDIT_MODE:
            cert_mode = CourseMode.VERIFIED

        if template_file is not None:
            template_pdf = template_file
        elif mode_is_verified and user_is_verified:
            template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(id=course_id)
        elif mode_is_verified and not user_is_verified:
            template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
            if CourseMode.mode_for_course(course_id, CourseMode.HONOR):
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                unverified = True
        else:
            # honor code and audit students
            template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
        if forced_grade:
            grade["grade"] = forced_grade

        LOGGER.info(
            (
                u"Certificate generated for student %s in the course: %s with template: %s. "
                u"given template: %s, "
                u"user is verified: %s, "
                u"mode is verified: %s"
            ),
            student.username,
            unicode(course_id),
            template_pdf,
            template_file,
            user_is_verified,
            mode_is_verified,
        )

        cert, created = GeneratedCertificate.objects.get_or_create(
            user=student, course_id=course_id
        )  # pylint: disable=no-member

        cert.mode = cert_mode
        cert.user = student
        cert.grade = grade["percent"]
        cert.course_id = course_id
        cert.name = profile_name
        cert.download_url = ""

        # Strip HTML from grade range label
        grade_contents = grade.get("grade", None)
        try:
            grade_contents = lxml.html.fromstring(grade_contents).text_content()
            passing = True
        except (TypeError, XMLSyntaxError, ParserError) as exc:
            LOGGER.info(
                (
                    u"Could not retrieve grade for student %s "
                    u"in the course '%s' "
                    u"because an exception occurred while parsing the "
                    u"grade contents '%s' as HTML. "
                    u"The exception was: '%s'"
                ),
                student.id,
                unicode(course_id),
                grade_contents,
                unicode(exc),
            )

            # Log if the student is whitelisted
            if is_whitelisted:
                LOGGER.info(u"Student %s is whitelisted in '%s'", student.id, unicode(course_id))
                passing = True
            else:
                passing = False

        # If this user's enrollment is not eligible to receive a
        # certificate, mark it as such for reporting and
        # analytics. Only do this if the certificate is new, or
        # already marked as ineligible -- we don't want to mark
        # existing audit certs as ineligible.
        cutoff = settings.AUDIT_CERT_CUTOFF_DATE
        if (cutoff and cert.created_date >= cutoff) and not is_eligible_for_certificate:
            cert.status = CertificateStatuses.audit_passing if passing else CertificateStatuses.audit_notpassing
            cert.save()
            LOGGER.info(
                u"Student %s with enrollment mode %s is not eligible for a certificate.", student.id, enrollment_mode
            )
            return cert
        # If they are not passing, short-circuit and don't generate cert
        elif not passing:
            cert.status = status.notpassing
            cert.save()

            LOGGER.info(
                (
                    u"Student %s does not have a grade for '%s', "
                    u"so their certificate status has been set to '%s'. "
                    u"No certificate generation task was sent to the XQueue."
                ),
                student.id,
                unicode(course_id),
                cert.status,
            )
            return cert

        # Check to see whether the student is on the the embargoed
        # country restricted list. If so, they should not receive a
        # certificate -- set their status to restricted and log it.
        if self.restricted.filter(user=student).exists():
            cert.status = status.restricted
            cert.save()

            LOGGER.info(
                (
                    u"Student %s is in the embargoed country restricted "
                    u"list, so their certificate status has been set to '%s' "
                    u"for the course '%s'. "
                    u"No certificate generation task was sent to the XQueue."
                ),
                student.id,
                cert.status,
                unicode(course_id),
            )
            return cert

        if unverified:
            cert.status = status.unverified
            cert.save()
            LOGGER.info(
                (
                    u"User %s has a verified enrollment in course %s "
                    u"but is missing ID verification. "
                    u"Certificate status has been set to unverified"
                ),
                student.id,
                unicode(course_id),
            )
            return cert

        # Finally, generate the certificate and send it off.
        return self._generate_cert(cert, course, student, grade_contents, template_pdf, generate_pdf)
Example #13
0
    def handle(self, *args, **options):
        if os.path.exists(options['output']):
            raise CommandError("File {0} already exists".format(
                options['output']))

        status_interval = 100

        # parse out the course into a coursekey
        if options['course']:
            try:
                course_key = CourseKey.from_string(options['course'])
            # if it's not a new-style course key, parse it from an old-style
            # course key
            except InvalidKeyError:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(
                    options['course'])

        print "Fetching enrolled students for {0}".format(course_key)
        enrolled_students = User.objects.filter(
            courseenrollment__course_id=course_key)
        factory = RequestMock()
        request = factory.get('/')

        total = enrolled_students.count()
        print "Total enrolled: {0}".format(total)
        course = courses.get_course_by_id(course_key)
        total = enrolled_students.count()
        start = datetime.datetime.now()
        rows = []
        header = None
        print "Fetching certificate data"
        cert_grades = {
            cert.user.username: cert.grade
            for cert in list(
                GeneratedCertificate.objects.filter(  # pylint: disable=no-member
                    course_id=course_key).prefetch_related('user'))
        }
        print "Grading students"
        for count, student in enumerate(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, __ = divmod(remainder, 60)
                print "{0}/{1} completed ~{2:02}:{3:02}m remaining".format(
                    count, total, hours, minutes)
                start = datetime.datetime.now()
            request.user = student
            grade = course_grades.summary(student, course)
            if not header:
                header = [
                    section['label'] for section in grade[u'section_breakdown']
                ]
                rows.append(
                    ["email", "username", "certificate-grade", "grade"] +
                    header)
            percents = {
                section['label']: section['percent']
                for section in grade[u'section_breakdown']
            }
            row_percents = [percents[label] for label in header]
            if student.username in cert_grades:
                rows.append([
                    student.email, student.username,
                    cert_grades[student.username], grade['percent']
                ] + row_percents, )
            else:
                rows.append(
                    [student.email, student.username, "N/A", grade['percent']
                     ] + row_percents)
        with open(options['output'], 'wb') as f:
            writer = csv.writer(f)
            writer.writerows(rows)
Example #14
0
    def handle(self, *args, **options):
        if os.path.exists(options['output']):
            raise CommandError("File {0} already exists".format(
                options['output']))

        STATUS_INTERVAL = 100

        # parse out the course into a coursekey
        if options['course']:
            try:
                course_key = CourseKey.from_string(options['course'])
            # if it's not a new-style course key, parse it from an old-style
            # course key
            except InvalidKeyError:
                course_key = SlashSeparatedCourseKey.from_deprecated_string(options['course'])

        print "Fetching enrolled students for {0}".format(course_key)
        enrolled_students = User.objects.filter(
            courseenrollment__course_id=course_key
        )
        factory = RequestMock()
        request = factory.get('/')

        total = enrolled_students.count()
        print "Total enrolled: {0}".format(total)
        course = courses.get_course_by_id(course_key)
        total = enrolled_students.count()
        start = datetime.datetime.now()
        rows = []
        header = None
        print "Fetching certificate data"
        cert_grades = {
            cert.user.username: cert.grade
            for cert in list(
                GeneratedCertificate.objects.filter(  # pylint: disable=no-member
                    course_id=course_key
                ).prefetch_related('user')
            )
        }
        print "Grading students"
        for count, student in enumerate(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, __ = divmod(remainder, 60)
                print "{0}/{1} completed ~{2:02}:{3:02}m remaining".format(
                    count, total, hours, minutes)
                start = datetime.datetime.now()
            request.user = student
            grade = course_grades.summary(student, request, course)
            if not header:
                header = [section['label'] for section in grade[u'section_breakdown']]
                rows.append(["email", "username", "certificate-grade", "grade"] + header)
            percents = {section['label']: section['percent'] for section in grade[u'section_breakdown']}
            row_percents = [percents[label] for label in header]
            if student.username in cert_grades:
                rows.append([student.email, student.username, cert_grades[student.username], grade['percent']] + row_percents)
            else:
                rows.append([student.email, student.username, "N/A", grade['percent']] + row_percents)
        with open(options['output'], 'wb') as f:
            writer = csv.writer(f)
            writer.writerows(rows)