Ejemplo n.º 1
0
def send_composite_outcome(user_id, course_id, assignment_id, version):
    """
    Calculate and transmit the score for a composite module (such as a
    vertical).

    A composite module may contain multiple problems, so we need to
    calculate the total points earned and possible for all child problems. This
    requires calculating the scores for the whole course, which is an expensive
    operation.

    Callers should be aware that the score calculation code accesses the latest
    scores from the database. This can lead to a race condition between a view
    that updates a user's score and the calculation of the grade. If the Celery
    task attempts to read the score from the database before the view exits (and
    its transaction is committed), it will see a stale value. Care should be
    taken that this task is not triggered until the view exits.

    The GradedAssignment model has a version_number field that is incremented
    whenever the score is updated. It is used by this method for two purposes.
    First, it allows the task to exit if it detects that it has been superseded
    by another task that will transmit the score for the same assignment.
    Second, it prevents a race condition where two tasks calculate different
    scores for a single assignment, and may potentially update the campus LMS
    in the wrong order.
    """
    assignment = GradedAssignment.objects.get(id=assignment_id)
    if version != assignment.version_number:
        log.info(
            "Score passback for GradedAssignment %s skipped. More recent score available.",
            assignment.id
        )
        return
    course_key = CourseKey.from_string(course_id)
    mapped_usage_key = assignment.usage_key.map_into_course(course_key)
    user = User.objects.get(id=user_id)
    course = modulestore().get_course(course_key, depth=0)
    course_grade = CourseGradeFactory().read(user, course)
    earned, possible = course_grade.score_for_module(mapped_usage_key)
    if possible == 0:
        weighted_score = 0
    else:
        weighted_score = float(earned) / float(possible)

    assignment = GradedAssignment.objects.get(id=assignment_id)
    if assignment.version_number == version:
        outcomes.send_score_update(assignment, weighted_score)
Ejemplo n.º 2
0
def send_composite_outcome(user_id, course_id, assignment_id, version):
    """
    Calculate and transmit the score for a composite module (such as a
    vertical).

    A composite module may contain multiple problems, so we need to
    calculate the total points earned and possible for all child problems. This
    requires calculating the scores for the whole course, which is an expensive
    operation.

    Callers should be aware that the score calculation code accesses the latest
    scores from the database. This can lead to a race condition between a view
    that updates a user's score and the calculation of the grade. If the Celery
    task attempts to read the score from the database before the view exits (and
    its transaction is committed), it will see a stale value. Care should be
    taken that this task is not triggered until the view exits.

    The GradedAssignment model has a version_number field that is incremented
    whenever the score is updated. It is used by this method for two purposes.
    First, it allows the task to exit if it detects that it has been superseded
    by another task that will transmit the score for the same assignment.
    Second, it prevents a race condition where two tasks calculate different
    scores for a single assignment, and may potentially update the campus LMS
    in the wrong order.
    """
    assignment = GradedAssignment.objects.get(id=assignment_id)
    if version != assignment.version_number:
        log.info(
            "Score passback for GradedAssignment %s skipped. More recent score available.",
            assignment.id)
        return
    course_key = CourseKey.from_string(course_id)
    mapped_usage_key = assignment.usage_key.map_into_course(course_key)
    user = User.objects.get(id=user_id)
    course = modulestore().get_course(course_key, depth=0)
    course_grade = CourseGradeFactory().create(user, course)
    earned, possible = course_grade.score_for_module(mapped_usage_key)
    if possible == 0:
        weighted_score = 0
    else:
        weighted_score = float(earned) / float(possible)

    assignment = GradedAssignment.objects.get(id=assignment_id)
    if assignment.version_number == version:
        outcomes.send_score_update(assignment, weighted_score)
Ejemplo n.º 3
0
def get_user_grades(user_id, course_str):
    """
    Get a single user's grades for  course. 
    """
    user = USER_MODEL.objects.get(id=user_id)
    course_key = CourseKey.from_string(str(course_str))
    course = courses.get_course(course_key)
    course_grade = CourseGradeFactory().update(user, course)
    course_structure = get_course_in_cache(course.id)
    courseware_summary = course_grade.chapter_grades.values()
    grade_summary = course_grade.summary
    grades_schema = {}
    courseware_summary = course_grade.chapter_grades.items()
    chapter_schema = {}
    for key, chapter in courseware_summary:
        subsection_schema = {}
        for section in chapter['sections']:
            section_children = course_structure.get_children(section.location)
            verticals = course_structure.get_children(section.location)
            vertical_schema = {}
            for vertical_key in verticals:
                sections_scores = {}
                problem_keys = course_structure.get_children(vertical_key)
                for problem_key in problem_keys:
                    if problem_key in section.problem_scores:
                        problem_score = section.problem_scores[problem_key]
                        xblock_content_url = reverse(
                            'courseware.views.views.render_xblock',
                            kwargs={'usage_key_string': unicode(problem_key)},
                        )
                        xblock_structure_url = generate_xblock_structure_url(
                            course_str, problem_key, user)
                        sections_scores[str(problem_key)] = {
                            "date":
                            problem_score.first_attempted
                            if problem_score.first_attempted is not None else
                            "Not attempted",
                            "earned":
                            problem_score.earned,
                            "possible":
                            problem_score.possible,
                            "xblock_content_url":
                            "{}{}".format(settings.LMS_ROOT_URL,
                                          xblock_content_url),
                            "xblock_structure_url":
                            "{}{}".format(settings.LMS_ROOT_URL,
                                          xblock_structure_url)
                        }
                    else:
                        sections_scores[str(
                            problem_key)] = "This block has no grades"
                vertical_structure_url = generate_xblock_structure_url(
                    course_str, vertical_key, user)
                vertical_schema[str(vertical_key)] = {
                    'problem_blocks': sections_scores,
                    "vertical_structure_url": vertical_structure_url
                }
            subsection_structure_url = generate_xblock_structure_url(
                course_str, section.location, user)
            subsection_schema[str(section.location)] = {
                "verticals": vertical_schema,
                "section_score":
                course_grade.score_for_module(section.location),
                "subsection_structure_url": subsection_structure_url
            }
        chapter_structure_url = generate_xblock_structure_url(
            course_str, key, user)
        chapter_schema[str(key)] = {
            "sections": subsection_schema,
            "chapter_structure_url": chapter_structure_url
        }

    return chapter_schema