Ejemplo n.º 1
0
def set_score(submission_uuid,
              points_earned,
              points_possible,
              annotation_creator=None,
              annotation_type=None,
              annotation_reason=None):
    """Set a score for a particular submission.

    Sets the score for a particular submission. This score is calculated
    externally to the API.

    Args:
        submission_uuid (str): UUID for the submission (must exist).
        points_earned (int): The earned points for this submission.
        points_possible (int): The total points possible for this particular student item.

        annotation_creator (str): An optional field for recording who gave this particular score
        annotation_type (str): An optional field for recording what type of annotation should be created,
                                e.g. "staff_override".
        annotation_reason (str): An optional field for recording why this score was set to its value.

    Returns:
        None

    Raises:
        SubmissionInternalError: Thrown if there was an internal error while
            attempting to save the score.
        SubmissionRequestError: Thrown if the given student item or submission
            are not found.

    Examples:
        >>> set_score("a778b933-9fb3-11e3-9c0f-040ccee02800", 11, 12)
        {
            'student_item': 2,
            'submission': 1,
            'points_earned': 11,
            'points_possible': 12,
            'created_at': datetime.datetime(2014, 2, 7, 20, 6, 42, 331156, tzinfo=<UTC>)
        }

    """
    try:
        submission_model = _get_submission_model(submission_uuid)
    except Submission.DoesNotExist as error:
        raise SubmissionNotFoundError(
            f"No submission matching uuid {submission_uuid}") from error
    except DatabaseError as error:
        error_msg = "Could not retrieve submission {}.".format(submission_uuid)
        logger.exception(error_msg)
        raise SubmissionRequestError(msg=error_msg) from error

    score = ScoreSerializer(
        data={
            "student_item": submission_model.student_item.pk,
            "submission": submission_model.pk,
            "points_earned": points_earned,
            "points_possible": points_possible,
        })
    if not score.is_valid():
        logger.exception(score.errors)
        raise SubmissionInternalError(score.errors)

    # When we save the score, a score summary will be created if
    # it does not already exist.
    # When the database's isolation level is set to repeatable-read,
    # it's possible for a score summary to exist for this student item,
    # even though we cannot retrieve it.
    # In this case, we assume that someone else has already created
    # a score summary and ignore the error.
    try:
        with transaction.atomic():
            score_model = score.save()
            _log_score(score_model)
            if annotation_creator is not None:
                score_annotation = ScoreAnnotation(
                    score=score_model,
                    creator=annotation_creator,
                    annotation_type=annotation_type,
                    reason=annotation_reason)
                score_annotation.save()
        # Send a signal out to any listeners who are waiting for scoring events.
        score_set.send(
            sender=None,
            points_possible=points_possible,
            points_earned=points_earned,
            anonymous_user_id=submission_model.student_item.student_id,
            course_id=submission_model.student_item.course_id,
            item_id=submission_model.student_item.item_id,
            created_at=score_model.created_at,
        )
    except IntegrityError:
        pass
Ejemplo n.º 2
0
def set_score(submission_uuid, points_earned, points_possible):
    """Set a score for a particular submission.

    Sets the score for a particular submission. This score is calculated
    externally to the API.

    Args:
        submission_uuid (str): UUID for the submission (must exist).
        points_earned (int): The earned points for this submission.
        points_possible (int): The total points possible for this particular student item.

    Returns:
        None

    Raises:
        SubmissionInternalError: Thrown if there was an internal error while
            attempting to save the score.
        SubmissionRequestError: Thrown if the given student item or submission
            are not found.

    Examples:
        >>> set_score("a778b933-9fb3-11e3-9c0f-040ccee02800", 11, 12)
        {
            'student_item': 2,
            'submission': 1,
            'points_earned': 11,
            'points_possible': 12,
            'created_at': datetime.datetime(2014, 2, 7, 20, 6, 42, 331156, tzinfo=<UTC>)
        }

    """
    try:
        submission_model = Submission.objects.get(uuid=submission_uuid)
    except Submission.DoesNotExist:
        raise SubmissionNotFoundError(
            u"No submission matching uuid {}".format(submission_uuid)
        )
    except DatabaseError:
        error_msg = u"Could not retrieve student item: {} or submission {}.".format(
            submission_uuid
        )
        logger.exception(error_msg)
        raise SubmissionRequestError(msg=error_msg)

    score = ScoreSerializer(
        data={
            "student_item": submission_model.student_item.pk,
            "submission": submission_model.pk,
            "points_earned": points_earned,
            "points_possible": points_possible,
        }
    )
    if not score.is_valid():
        logger.exception(score.errors)
        raise SubmissionInternalError(score.errors)

    # When we save the score, a score summary will be created if
    # it does not already exist.
    # When the database's isolation level is set to repeatable-read,
    # it's possible for a score summary to exist for this student item,
    # even though we cannot retrieve it.
    # In this case, we assume that someone else has already created
    # a score summary and ignore the error.
    try:
        score_model = score.save()
        _log_score(score_model)
        # Send a signal out to any listeners who are waiting for scoring events.
        score_set.send(
            sender=None,
            points_possible=points_possible,
            points_earned=points_earned,
            anonymous_user_id=submission_model.student_item.student_id,
            course_id=submission_model.student_item.course_id,
            item_id=submission_model.student_item.item_id,
        )
    except IntegrityError:
        pass