def finalize_expired_submission(sub): """ Expire submissions by posting back to LMS with error message. Input: timed_out_list from check_if_expired method Output: Success code. """ grader_dict = { 'score': 0, 'feedback': error_template.format(errors="Error scoring submission."), 'status': GraderStatus.failure, 'grader_id': "0", 'grader_type': sub.next_grader_type, 'confidence': 1, 'submission_id' : sub.id, } sub.state = SubmissionState.finished sub.save() grade = create_grader(grader_dict,sub) statsd.increment("open_ended_assessment.grading_controller.expire_submissions.finalize_expired_submission", tags=[ "course:{0}".format(sub.course_id), "location:{0}".format(sub.location), 'grader_type:{0}'.format(sub.next_grader_type) ]) return True
def create_and_handle_grader_object(grader_dict): """ Creates a Grader object and associates it with a given submission Input is grader dictionary with keys: feedback, status, grader_id, grader_type, confidence, score,submission_id, errors Feedback should be a dictionary with as many keys as needed. Errors is a string containing errors. """ for tag in ["feedback", "status", "grader_id", "grader_type", "confidence", "score", "submission_id", "errors"]: if tag not in grader_dict: return False, "{0} tag not in input dictionary.".format(tag) try: sub = Submission.objects.get(id=int(grader_dict['submission_id'])) except: return False, "Error getting submission." try: grader_dict['feedback'] = json.loads(grader_dict['feedback']) except: pass if not isinstance(grader_dict['feedback'], dict): grader_dict['feedback'] = {'feedback': grader_dict['feedback']} for k in grader_dict['feedback']: grader_dict['feedback'][k] = util.sanitize_html(grader_dict['feedback'][k]) if grader_dict['status'] == GraderStatus.failure: grader_dict['feedback'] = ' '.join(grader_dict['errors']) grader_dict['feedback'] = json.dumps(grader_dict['feedback']) grade = create_grader(grader_dict, sub) #Check to see if rubric scores were passed to the function, and handle if so. if 'rubric_scores_complete' in grader_dict and 'rubric_scores' in grader_dict: try: grader_dict['rubric_scores']=json.loads(grader_dict['rubric_scores']) except: pass if grader_dict['rubric_scores_complete'] in ['True', "TRUE", 'true', True]: grader_dict['rubric_scores']=[int(r) for r in grader_dict['rubric_scores']] try: rubric_functions.generate_rubric_object(grade,grader_dict['rubric_scores'], sub.rubric) except: log.exception("Problem with getting rubric scores from dict : {0}".format(grader_dict)) #TODO: Need some kind of logic somewhere else to handle setting next_grader sub.previous_grader_type = grade.grader_type sub.next_grader_type = grade.grader_type #check to see if submission is flagged. If so, put it in a flagged state submission_is_flagged = grader_dict.get('is_submission_flagged', False) if submission_is_flagged: sub.state = SubmissionState.flagged else: #TODO: Some kind of logic to decide when sub is finished grading. #If we are calling this after a basic check and the score is 0, that means that the submission is bad, so mark as finished if(grade.status_code == GraderStatus.success and grade.grader_type in ["BC"] and grade.score==0): sub.state = SubmissionState.finished #If submission is ML or IN graded, and was successful, state is finished elif(grade.status_code == GraderStatus.success and grade.grader_type in ["IN", "ML"]): sub.state = SubmissionState.finished elif(grade.status_code == GraderStatus.success and grade.grader_type in ["PE"]): #If grading type is Peer, and was successful, check to see how many other times peer grading has succeeded. successful_peer_grader_count = sub.get_successful_peer_graders().count() #If number of successful peer graders equals the needed count, finalize submission. if successful_peer_grader_count >= settings.PEER_GRADER_COUNT: sub.state = SubmissionState.finished else: sub.state = SubmissionState.waiting_to_be_graded #If something fails, immediately mark it for regrading #TODO: Get better logic for handling failure cases elif(grade.status_code == GraderStatus.failure and sub.state == SubmissionState.being_graded): number_of_failures = sub.get_unsuccessful_graders().count() #If it has failed too many times, just return an error if number_of_failures > settings.MAX_NUMBER_OF_TIMES_TO_RETRY_GRADING: finalize_expired_submission(sub) else: sub.state = SubmissionState.waiting_to_be_graded #Increment statsd whenever a grader object is saved. statsd.increment("open_ended_assessment.grading_controller.controller.create_grader_object", tags=["submission_state:{0}".format(sub.state), "grader_type:{0}".format(grade.grader_type), "grader_status:{0}".format(grade.status_code), "location:{0}".format(sub.location), "course_id:{0}".format(sub.course_id), "next_grader_type:{0}".format(sub.next_grader_type), "score:{0}".format(grade.score), ] ) sub.save() #Insert timing finalization code finalize_timing(sub, grade) return True, {'submission_id': sub.xqueue_submission_id, 'submission_key': sub.xqueue_submission_key}