def test_create_item_multiple_available(self): # Bugfix TIM-572 submitter_sub = sub_api.create_submission(self.STUDENT_ITEM, 'test answer') submitter_workflow = PeerWorkflow.objects.create( student_id=self.STUDENT_ITEM['student_id'], item_id=self.STUDENT_ITEM['item_id'], course_id=self.STUDENT_ITEM['course_id'], submission_uuid=submitter_sub['uuid']) scorer_sub = sub_api.create_submission(self.OTHER_STUDENT, 'test answer 2') scorer_workflow = PeerWorkflow.objects.create( student_id=self.OTHER_STUDENT['student_id'], item_id=self.OTHER_STUDENT['item_id'], course_id=self.OTHER_STUDENT['course_id'], submission_uuid=scorer_sub['uuid']) for _ in range(2): PeerWorkflowItem.objects.create( scorer=scorer_workflow, author=submitter_workflow, submission_uuid=submitter_sub['uuid']) # This used to cause an error when `get_or_create` returned multiple workflow items PeerWorkflow.create_item(scorer_workflow, submitter_sub['uuid'])
def create_peer_workflow_item(scorer_submission_uuid, submission_uuid): """ Begin peer-assessing a particular submission. Note that this does NOT pick the submission from the prioritized list of available submissions. Mainly useful for testing. Args: scorer_submission_uuid (str): The ID of the scoring student. submission_uuid (str): The unique identifier of the submission being scored Returns: None Raises: PeerAssessmentWorkflowError: Could not find the workflow for the student. PeerAssessmentInternalError: Could not create the peer workflow item. """ workflow = PeerWorkflow.get_by_submission_uuid(scorer_submission_uuid) PeerWorkflow.create_item(workflow, submission_uuid)
def create_peer_workflow_item(scorer_submission_uuid, submission_uuid): """ Begin peer-assessing a particular submission. Note that this does NOT pick the submission from the prioritized list of available submissions. Mainly useful for testing. Args: scorer_submission_uuid (str): The ID of the scoring student. submission_uuid (str): The unique identifier of the submission being scored Returns: None Raises: PeerAssessmentWorkflowError: Could not find the workflow for the student. PeerAssessmentInternalError: Could not create the peer workflow item. """ workflow = PeerWorkflow.get_by_submission_uuid(scorer_submission_uuid) PeerWorkflow.create_item(workflow, submission_uuid)
def test_find_active_assessments(self): buffy_answer, _ = self._create_student_and_submission("Buffy", "Buffy's answer") xander_answer, _ = self._create_student_and_submission("Xander", "Xander's answer") # Check for a workflow for Buffy. buffy_workflow = PeerWorkflow.get_by_submission_uuid(buffy_answer['uuid']) self.assertIsNotNone(buffy_workflow) # Check to see if Buffy is actively reviewing Xander's submission. # She isn't so we should get back no uuid. submission_uuid = buffy_workflow.find_active_assessments() self.assertIsNone(submission_uuid) # Buffy is going to review Xander's submission, so create a workflow # item for Buffy. PeerWorkflow.create_item(buffy_workflow, xander_answer["uuid"]) # Check to see if Buffy is still actively reviewing Xander's submission. submission_uuid = buffy_workflow.find_active_assessments() self.assertEqual(xander_answer["uuid"], submission_uuid)
def test_get_submission_for_over_grading(self): buffy_answer, _ = self._create_student_and_submission("Buffy", "Buffy's answer") xander_answer, _ = self._create_student_and_submission("Xander", "Xander's answer") willow_answer, _ = self._create_student_and_submission("Willow", "Willow's answer") buffy_workflow = PeerWorkflow.get_by_submission_uuid(buffy_answer['uuid']) xander_workflow = PeerWorkflow.get_by_submission_uuid(xander_answer['uuid']) willow_workflow = PeerWorkflow.get_by_submission_uuid(willow_answer['uuid']) # Get a bunch of workflow items opened up. PeerWorkflow.create_item(buffy_workflow, xander_answer["uuid"]) PeerWorkflow.create_item(willow_workflow, xander_answer["uuid"]) PeerWorkflow.create_item(xander_workflow, xander_answer["uuid"]) PeerWorkflow.create_item(buffy_workflow, willow_answer["uuid"]) PeerWorkflow.create_item(xander_workflow, willow_answer["uuid"]) # Get the next submission for review submission_uuid = xander_workflow.get_submission_for_over_grading() if not (buffy_answer["uuid"] == submission_uuid or willow_answer["uuid"] == submission_uuid): self.fail("Submission was not Buffy or Willow's.")
def test_create_item_multiple_available(self): # Bugfix TIM-572 submitter_sub = sub_api.create_submission(self.STUDENT_ITEM, "test answer") submitter_workflow = PeerWorkflow.objects.create( student_id=self.STUDENT_ITEM["student_id"], item_id=self.STUDENT_ITEM["item_id"], course_id=self.STUDENT_ITEM["course_id"], submission_uuid=submitter_sub["uuid"], ) scorer_sub = sub_api.create_submission(self.OTHER_STUDENT, "test answer 2") scorer_workflow = PeerWorkflow.objects.create( student_id=self.OTHER_STUDENT["student_id"], item_id=self.OTHER_STUDENT["item_id"], course_id=self.OTHER_STUDENT["course_id"], submission_uuid=scorer_sub["uuid"], ) for _ in range(2): PeerWorkflowItem.objects.create( scorer=scorer_workflow, author=submitter_workflow, submission_uuid=submitter_sub["uuid"] ) # This used to cause an error when `get_or_create` returned multiple workflow items PeerWorkflow.create_item(scorer_workflow, submitter_sub["uuid"])
def get_submission_to_assess(submission_uuid, graded_by): """Get a submission to peer evaluate. Retrieves a submission for assessment for the given student. This will not return a submission submitted by the requesting scorer. Submissions are returned based on how many assessments are still required, and if there are peers actively assessing a particular submission. If there are no submissions requiring assessment, a submission may be returned that will be 'over graded', and the assessment will not be counted towards the overall grade. Args: submission_uuid (str): The submission UUID from the student requesting a submission for assessment. This is used to explicitly avoid giving the student their own submission, and determines the associated Peer Workflow. graded_by (int): The number of assessments a submission requires before it has completed the peer assessment process. Returns: dict: A peer submission for assessment. This contains a 'student_item', 'attempt_number', 'submitted_at', 'created_at', and 'answer' field to be used for assessment. Raises: PeerAssessmentRequestError: Raised when the request parameters are invalid for the request. PeerAssessmentInternalError: Raised when there is an internal error retrieving peer workflow information. PeerAssessmentWorkflowError: Raised when an error occurs because this function, or the student item, is not in the proper workflow state to retrieve a peer submission. Examples: >>> get_submission_to_assess("abc123", 3) { 'student_item': 2, 'attempt_number': 1, 'submitted_at': datetime.datetime(2014, 1, 29, 23, 14, 52, 649284, tzinfo=<UTC>), 'created_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 668850, tzinfo=<UTC>), 'answer': u'The answer is 42.' } """ workflow = PeerWorkflow.get_by_submission_uuid(submission_uuid) if not workflow: raise PeerAssessmentWorkflowError( u"A Peer Assessment Workflow does not exist for the student " u"with submission UUID {}".format(submission_uuid) ) peer_submission_uuid = workflow.find_active_assessments() # If there is an active assessment for this user, get that submission, # otherwise, get the first assessment for review, otherwise, # get the first submission available for over grading ("over-grading"). if peer_submission_uuid is None: peer_submission_uuid = workflow.get_submission_for_review(graded_by) if peer_submission_uuid is None: peer_submission_uuid = workflow.get_submission_for_over_grading() if peer_submission_uuid: try: submission_data = sub_api.get_submission(peer_submission_uuid) PeerWorkflow.create_item(workflow, peer_submission_uuid) _log_workflow(peer_submission_uuid, workflow) return submission_data except sub_api.SubmissionNotFoundError: error_message = ( u"Could not find a submission with the uuid {} for student {} " u"in the peer workflow." ).format(peer_submission_uuid, workflow.student_id) logger.exception(error_message) raise PeerAssessmentWorkflowError(error_message) else: logger.info( u"No submission found for {} to assess ({}, {})" .format( workflow.student_id, workflow.course_id, workflow.item_id, ) ) return None
def get_submission_to_assess(submission_uuid, graded_by): """Get a submission to peer evaluate. Retrieves a submission for assessment for the given student. This will not return a submission submitted by the requesting scorer. Submissions are returned based on how many assessments are still required, and if there are peers actively assessing a particular submission. If there are no submissions requiring assessment, a submission may be returned that will be 'over graded', and the assessment will not be counted towards the overall grade. Args: submission_uuid (str): The submission UUID from the student requesting a submission for assessment. This is used to explicitly avoid giving the student their own submission, and determines the associated Peer Workflow. graded_by (int): The number of assessments a submission requires before it has completed the peer assessment process. Returns: dict: A peer submission for assessment. This contains a 'student_item', 'attempt_number', 'submitted_at', 'created_at', and 'answer' field to be used for assessment. Raises: PeerAssessmentRequestError: Raised when the request parameters are invalid for the request. PeerAssessmentInternalError: Raised when there is an internal error retrieving peer workflow information. PeerAssessmentWorkflowError: Raised when an error occurs because this function, or the student item, is not in the proper workflow state to retrieve a peer submission. Examples: >>> get_submission_to_assess("abc123", 3) { 'student_item': 2, 'attempt_number': 1, 'submitted_at': datetime.datetime(2014, 1, 29, 23, 14, 52, 649284, tzinfo=<UTC>), 'created_at': datetime.datetime(2014, 1, 29, 17, 14, 52, 668850, tzinfo=<UTC>), 'answer': u'The answer is 42.' } """ workflow = PeerWorkflow.get_by_submission_uuid(submission_uuid) if not workflow: raise PeerAssessmentWorkflowError( u"A Peer Assessment Workflow does not exist for the student " u"with submission UUID {}".format(submission_uuid) ) peer_submission_uuid = workflow.find_active_assessments() # If there is an active assessment for this user, get that submission, # otherwise, get the first assessment for review, otherwise, # get the first submission available for over grading ("over-grading"). if peer_submission_uuid is None: peer_submission_uuid = workflow.get_submission_for_review(graded_by) if peer_submission_uuid is None: peer_submission_uuid = workflow.get_submission_for_over_grading() if peer_submission_uuid: try: submission_data = sub_api.get_submission(peer_submission_uuid) PeerWorkflow.create_item(workflow, peer_submission_uuid) _log_workflow(peer_submission_uuid, workflow) return submission_data except sub_api.SubmissionNotFoundError: error_message = ( u"Could not find a submission with the uuid {} for student {} " u"in the peer workflow." ).format(peer_submission_uuid, workflow.student_id) logger.exception(error_message) raise PeerAssessmentWorkflowError(error_message) else: logger.info( u"No submission found for {} to assess ({}, {})" .format( workflow.student_id, workflow.course_id, workflow.item_id, ) ) return None
def test_create_workflow_item_error(self, mock_filter): mock_filter.side_effect = DatabaseError("Oh no.") tim_answer, tim = self._create_student_and_submission("Tim", "Tim's answer", MONDAY) PeerWorkflow.create_item(tim, tim_answer['uuid'])