Beispiel #1
0
    def assert_team_submission_list(self, team_submissions,
                                    expected_submission_1,
                                    expected_submission_2):
        """
        Convenience method.
        Asserts that team_submissions has exactly two elements and that they are equal to
        expected_submission_1 and expected_submission_2
        """
        self.assertEqual(len(team_submissions), 2)
        self.assertEqual(
            {
                submission['team_submission_uuid']
                for submission in team_submissions
            },
            {str(expected_submission_1.uuid),
             str(expected_submission_2.uuid)})
        if team_submissions[0][
                'team_submission_uuid'] == expected_submission_1.uuid:
            team_submission_1, team_submission_2 = team_submissions
        else:
            team_submission_2, team_submission_1 = team_submissions

        self.assertDictEqual(
            TeamSubmissionSerializer(expected_submission_1).data,
            team_submission_1)
        self.assertDictEqual(
            TeamSubmissionSerializer(expected_submission_2).data,
            team_submission_2)
Beispiel #2
0
 def test_get_team_submission_for_team(self):
     """
     Test that calling team_api.get_team_submission_for_team returns the expected team submission
     """
     team_submission = self._make_team_submission(create_submissions=True)
     team_submission_dict = team_api.get_team_submission_for_team(
         COURSE_ID, ITEM_1_ID, TEAM_1_ID)
     self.assertDictEqual(team_submission_dict,
                          TeamSubmissionSerializer(team_submission).data)
Beispiel #3
0
def get_team_submission_for_team(course_id, item_id, team_id):
    """
    Returns a single team submission (serialized) for the given team in the given (course, item).

    Raises:
        - TeamSubmissionNotFoundError when no such team submission exists.
        - TeamSubmissionInternalError if there is some other error looking up the team submission.
    """
    team_submission = TeamSubmission.get_team_submission_by_course_item_team(
        course_id, item_id, team_id)
    return TeamSubmissionSerializer(team_submission).data
Beispiel #4
0
def get_team_submission(team_submission_uuid):
    """
    Returns a single, serialized, team submission for the given key.

    Raises:
        - TeamSubmissionNotFoundError when no such team submission exists.
        - TeamSubmissionInternalError if there is some other error looking up the team submission.
    """
    team_submission = TeamSubmission.get_team_submission_by_uuid(
        team_submission_uuid)
    return TeamSubmissionSerializer(team_submission).data
Beispiel #5
0
 def test_get_team_submission_from_individual_submission(self):
     """
     Test that calling team_api.get_team_submission_from_individual_submission returns the expected team submission
     """
     team_submission_model = self._make_team_submission(create_submissions=True)
     regular_submission_uuid = team_submission_model.submissions.first().uuid
     team_submission_dict = team_api.get_team_submission_from_individual_submission(regular_submission_uuid)
     self.assertDictEqual(
         team_submission_dict,
         TeamSubmissionSerializer(team_submission_model).data
     )
Beispiel #6
0
    def test_get_team_submission(self):
        """
        Test that calling team_api.get_team_submission returns the expected team submission
        """
        team_submission_model = self._make_team_submission(create_submissions=True)

        team_submission_dict = team_api.get_team_submission(team_submission_model.uuid)
        self.assertDictEqual(
            team_submission_dict,
            TeamSubmissionSerializer(team_submission_model).data
        )
Beispiel #7
0
def get_all_team_submissions(course_id, item_id):
    """
    Returns all of the (active) team submissions (serialized) in the given (course, item).

    Returns an empty iterable if no team submissions exist for this (course, item).

    Raises:
        - TeamSubmissionInternalError if there is some other error looking up the team submission.
    """
    team_submissions = TeamSubmission.get_all_team_submissions_for_course_item(
        course_id, item_id)
    return TeamSubmissionSerializer(team_submissions, many=True).data
def get_team_submission_for_student(student_item_dict):
    """
    Returns a single team submission (serialized). Looks up the team submission with an associated individual
    submission with the given student info.

    Raises:
        - TeamSubmissionNotFoundError when no such team submission exists.
        - TeamSubmissionInternalError if there is some other error looking up the team submission.
    """
    student_item = _api._get_or_create_student_item(student_item_dict)  # pylint: disable=protected-access
    team_submission = TeamSubmission.get_team_submission_by_student_item(
        student_item)
    return TeamSubmissionSerializer(team_submission).data
Beispiel #9
0
def get_team_submission_from_individual_submission(individual_submission_uuid):
    """
    Returns a single, serialized, team submission for the individual submission uuid.

    Raises:
        - TeamSubmissionNotFoundError when no such team submission exists.
        - TeamSubmissionInternalError if there is some other error looking up the team submission.
    """
    team_submission = TeamSubmission.objects.filter(
        submissions__uuid=individual_submission_uuid).first()
    if not team_submission:
        raise TeamSubmissionNotFoundError

    return TeamSubmissionSerializer(team_submission).data
Beispiel #10
0
    def test_team_submission_serializer(self):
        """
        Test that the non-trivial fields on TeamSerializer have been serialized correctly
        """
        serialized_data = TeamSubmissionSerializer(self.team_submission).data

        self.assertEqual(serialized_data['team_submission_uuid'],
                         str(self.team_submission.uuid))
        self.assertEqual(
            set(serialized_data['submission_uuids']),
            set(submission.uuid for submission in self.submissions),
        )
        self.assertEqual(serialized_data['submitted_at'],
                         self.team_submission.submitted_at)
        self.assertEqual(serialized_data['created_at'],
                         self.team_submission.created)
        self.assertEqual(serialized_data['attempt_number'],
                         self.team_submission.attempt_number)
        self.assertEqual(serialized_data['answer'], self.answer)
Beispiel #11
0
def create_submission_for_team(
    course_id,
    item_id,
    team_id,
    submitting_user_id,
    team_member_ids,
    answer,
    submitted_at=None,
    attempt_number=1,
    item_type='openassessment',
):
    """
    This api function:
      1. Creates a `TeamSubmission` record, and
      2. Creates `Submission` records for every member of the team by calling api.create_submission()

    This means that the ORA `SubmissionMixin` must first collect all of the files of the submitting user
    and the team into the `answer` dict.

    Parameters:
        - course_id (str): the course id for this team submission
        - item_id (str): the item id for this team submission
        - team_id (str): the team_id for the team for which we are making the submission
        - submitting_user_id (User): the user who has hit the "submit" button
        - team_member_ids (list of str): a list of the anonymous user ids associated with all members of the team
        - answer (json serializable object): string, dict, or other json-serializable object that represents the team's
                                             answer to the problem
        - submitted_at (datetime): (optional [default = now]) the datetime at which the team submission was submitted
        - attempt number (int): (optional [default = 1]) the attempt number for this submission
        - item_type (str): (optional [default = 'openassessment']) the type of item for which this submission is being
                                                                   submitted

    Returns:
        dict: A representation of the created TeamSubmission, with the following keys:
          'team_submission_uuid' Is the `uuid` field of the created `TeamSubmission`.
          'course_id' Is the ID of the course.
          'item_id' Is the ID of the item (e.g. the block).
          'team_id' Is the ID of the team.
          'submitted_by' Is the ID of the submitting user (same as `submitting_user_id`)
          'attempt_number' is the attempt number this submission represents for this question.
          'submitted_at' represents the time this submission was submitted, which can be configured, versus the...
          'created_at' date, which is when the submission is first created.
          'submission_uuids' Is a list of the UUIDs of each of the individual `Submission` records that is created.

    Raises:
        TeamSubmissionRequestError: Raised when there are validation errors for the
            student item or team submission. This can be caused by the student item
            missing required values, the submission being too long, the
            attempt_number is negative, or the given submitted_at time is invalid.
        SubmissionRequestError: Raised when there are validation errors for the underlying
            student item or submission. This can be caused by the same reason as
            the TeamSubmissionRequestError
        TeamSubmissionInternalError: Raised when submission access causes an
            internal error.
        TeamSubmissionInternalError: Raised when submission access causes an
            internal error when creating the underlying submissions.

    Examples:
        >>>course_id = "course_1"
        >>>item_id = "item_1"
        >>>team_id = "A Team"
        >>>submitting_user_id = "Tim"
        >>>team_member_ids = ["Alice", "Bob", "Carol", "Tim"]
        >>>answer = "The answer is 42."
        >>> )
        >>> create_submission_for_team(
                course_id, item_id, team_id, submitting_user_id, team_member_ids, answer, datetime.utcnow, 1
            )
        {
            'team_submission_uuid': 'blah',
            'course_id': "course_1",
            'item_id': "item_1",
            'team_id': "A Team",
            'submitted_by': "Tim",
            'attempt_number': 1,
            'submitted_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 649284 tzinfo=<UTC>),
            'created_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 668850, tzinfo=<UTC>),
            'answer': u'The answer is 42.',
            'submission_uuids': ['alice-uuid', 'bob-uuid', 'carol-uuid', 'tim-uuid'],
        }
    """

    # I have no clue what to do with attempt_number. The normal API checks if there are any duplicate submissions and
    # incrememnts attempt_number, but we prevent duplicate team submissions, so I can't copy that logic flow.
    # I thought maybe we should look for deleted submissions and incrememnt based of of that, but looking at
    # production data I can't find a single case where that happens.
    # For now ... I'm just gonna default it to 1?

    model_kwargs = {
        'course_id': course_id,
        'item_id': item_id,
        'team_id': team_id,
        'submitted_by': submitting_user_id,
        'attempt_number': attempt_number,
    }
    if submitted_at:
        model_kwargs["submitted_at"] = submitted_at

    try:
        team_submission_serializer = TeamSubmissionSerializer(
            data=model_kwargs, context={'answer': answer})
        if not team_submission_serializer.is_valid():
            raise TeamSubmissionRequestError(
                field_errors=team_submission_serializer.errors)
        team_submission = team_submission_serializer.save()
        _log_team_submission(team_submission_serializer.data)
    except DatabaseError as exc:
        error_message = "An error occurred while creating team submission {}: {}".format(
            model_kwargs, exc)
        logger.exception(error_message)
        raise TeamSubmissionInternalError(error_message)

    base_student_item_dict = {
        'course_id': course_id,
        'item_id': item_id,
        'item_type': item_type
    }
    for team_member_id in team_member_ids:
        team_member_student_item_dict = dict(base_student_item_dict)
        team_member_student_item_dict['student_id'] = team_member_id
        _api.create_submission(team_member_student_item_dict,
                               answer,
                               submitted_at=submitted_at,
                               attempt_number=attempt_number,
                               team_submission=team_submission)

    model_kwargs = {
        "answer": answer,
    }
    # We must serialize the model, since the existing serializer doesn't have info about the individual submissions
    model_serializer = TeamSubmissionSerializer(team_submission,
                                                context={"answer": answer})
    return model_serializer.data