def check_metadata_xml(request, course_prefix, course_suffix): xml = request.POST.get('metaXMLContent') if not xml: return HttpResponseBadRequest("No metaXMLContent provided") try: grader = AutoGrader(xml) except Exception as e: #Since this is just a validator, pass back all the exceptions return HttpResponseBadRequest(unicode(e)) return HttpResponse("Metadata XML is OK.\n" + unicode(grader))
def save_exam_ajax(request, course_prefix, course_suffix, create_or_edit="create", old_slug=""): course = request.common_page_data['course'] if course.mode == "ready": course = course.image slug = request.POST.get('slug', '') title = request.POST.get('title', '') description = request.POST.get('description', '') metaXMLContent = request.POST.get('metaXMLContent', '') htmlContent = request.POST.get('htmlContent', '') xmlImported = request.POST.get('xmlImported', '') due_date = request.POST.get('due_date', '') grace_period = request.POST.get('grace_period', '') partial_credit_deadline = request.POST.get('partial_credit_deadline', '') late_penalty = request.POST.get('late_penalty', '') num_subs_permitted = request.POST.get('num_subs_permitted', '') resubmission_penalty = request.POST.get('resubmission_penalty', '') assessment_type = request.POST.get('assessment_type', '') section = request.POST.get('section', '') invideo_val = request.POST.get('invideo', '') parent = request.POST.get('parent', 'none,none') if invideo_val and invideo_val == "true": invideo = True else: invideo = False #########Validation, lots of validation####### if not slug: return HttpResponseBadRequest("No URL identifier value provided") try: validate_slug(slug) except ValidationError as ve: return HttpResponseBadRequest(unicode(ve)) if not title: return HttpResponseBadRequest("No Title value provided") if not metaXMLContent: return HttpResponseBadRequest("No metadataXML provided") try: grader = AutoGrader(metaXMLContent) except Exception as e: #Since this is just a validator, pass back all the exceptions return HttpResponseBadRequest(unicode(e)) total_score = grader.points_possible if not htmlContent: return HttpResponseBadRequest("No Exam HTML provided") if not due_date: return HttpResponseBadRequest("No due date provided") if not grace_period: return HttpResponseBadRequest("No grace period provided") if not partial_credit_deadline: return HttpResponseBadRequest("No hard deadline provided") if not section: return HttpResponseBadRequest("Bad section provided!") try: contentsection = ContentSection.objects.get(id=section, course=course, is_deleted=False) except ContentSection.DoesNotExist: return HttpResponseBadRequest("Bad section provided!") dd = datetime.datetime.strptime(due_date, "%m/%d/%Y %H:%M") gp = datetime.datetime.strptime(grace_period, "%m/%d/%Y %H:%M") pcd = datetime.datetime.strptime(partial_credit_deadline, "%m/%d/%Y %H:%M") if assessment_type == "summative": autograde = True display_single = False grade_single = False exam_type = "problemset" elif assessment_type == "formative": autograde = True display_single = True grade_single = False #We will eventually want this to be True exam_type = "problemset" elif assessment_type == "interactive": autograde = True display_single = True grade_single = False exam_type = "interactive_exercise" elif assessment_type == "exam-autograde": autograde = True display_single = False grade_single = False exam_type = "exam" elif assessment_type == "exam-csv": autograde = False display_single = False grade_single = False exam_type = "exam" elif assessment_type == "survey": autograde = False display_single = False grade_single = False exam_type = "survey" else: return HttpResponseBadRequest("A bad assessment type (" + assessment_type + ") was provided") if not late_penalty: lp = 0 else: try: lp = int(late_penalty) except ValueError: return HttpResponseBadRequest("A non-numeric late penalty (" + late_penalty + ") was provided") if not num_subs_permitted: sp = 999 else: try: sp = int(num_subs_permitted) except ValueError: return HttpResponseBadRequest( "A non-numeric number of submissions permitted (" + sp + ") was provided") if not resubmission_penalty: rp = 0 else: try: rp = int(resubmission_penalty) except ValueError: return HttpResponseBadRequest( "A non-numeric resubmission penalty (" + resubmission_penalty + ") was provided") if parent and parent[:4] != 'none': parent_type, parent = parent.split(',') else: parent_type, parent = None, None #create or edit the Exam if create_or_edit == "create": if Exam.objects.filter(course=course, slug=slug, is_deleted=False).exists(): return HttpResponseBadRequest( "An exam with this URL identifier already exists in this course" ) exam_obj = Exam(course=course, slug=slug, title=title, description=description, html_content=htmlContent, xml_metadata=metaXMLContent, due_date=dd, assessment_type=assessment_type, mode="draft", total_score=total_score, grade_single=grade_single, grace_period=gp, partial_credit_deadline=pcd, late_penalty=lp, submissions_permitted=sp, resubmission_penalty=rp, exam_type=exam_type, autograde=autograde, display_single=display_single, invideo=invideo, section=contentsection, xml_imported=xmlImported) exam_obj.save() exam_obj.create_ready_instance() if parent_type: parent_ref = ContentGroup.groupable_types[parent_type].objects.get( id=long(parent)).image content_group_groupid = ContentGroup.add_parent( exam_obj.image.course, parent_type, parent_ref.image) ContentGroup.add_child(content_group_groupid, 'exam', exam_obj.image, display_style='list') return HttpResponse("Exam " + title + " created. \n" + unicode(grader)) else: try: #this is nasty code, I know. It should at least be moved into the model somehow exam_obj = Exam.objects.get(course=course, is_deleted=0, slug=old_slug) exam_obj.slug = slug exam_obj.title = title exam_obj.description = description exam_obj.html_content = htmlContent exam_obj.xml_metadata = metaXMLContent exam_obj.xml_imported = xmlImported exam_obj.due_date = dd exam_obj.total_score = total_score exam_obj.assessment_type = assessment_type exam_obj.grace_period = gp exam_obj.partial_credit_deadline = pcd exam_obj.late_penalty = lp exam_obj.submissions_permitted = sp exam_obj.resubmission_penalty = rp exam_obj.exam_type = exam_type exam_obj.autograde = autograde exam_obj.display_single = display_single exam_obj.grade_single = grade_single exam_obj.invideo = invideo exam_obj.section = contentsection exam_obj.save() exam_obj.commit() if parent_type: parent_ref = ContentGroup.groupable_types[ parent_type].objects.get(id=long(parent)).image content_group_parent = parent_ref.contentgroup_set.all() if content_group_parent: content_group_groupid = content_group_parent[0].group_id else: content_group_groupid = ContentGroup.add_parent( exam_obj.image.course, parent_type, parent_ref.image) ContentGroup.add_child(content_group_groupid, 'exam', exam_obj.image, display_style='list') return HttpResponse("Exam " + title + " saved. \n" + unicode(grader)) except Exam.DoesNotExist: return HttpResponseBadRequest( "No exam exists with URL identifier %s" % old_slug)
def collect_data(request, course_prefix, course_suffix, exam_slug): course = request.common_page_data['course'] user = request.user try: exam = Exam.objects.get(course=course, is_deleted=0, slug=exam_slug) except Exam.DoesNotExist: raise Http404 postdata = request.POST[ 'json_data'] #will return an error code to the user if either of these fail (throws 500) json_obj = json.loads(postdata) if exam.past_all_deadlines(): return HttpResponseBadRequest("Sorry! This submission is past the last deadline of %s" % \ datetime.datetime.strftime(exam.partial_credit_deadline, "%m/%d/%Y %H:%M PST")) attempt_number = exam.num_of_student_records(user) + 1 onpage = request.POST.get('onpage', '') record = ExamRecord(course=course, exam=exam, student=user, json_data=postdata, onpage=onpage, attempt_number=attempt_number, late=exam.past_due()) record.save() autograder = None if exam.exam_type == "survey": autograder = AutoGrader( "<null></null>", default_return=True ) #create a null autograder that always returns the "True" object elif exam.autograde: try: autograder = AutoGrader(exam.xml_metadata) except Exception as e: #Pass back all the exceptions so user can see return HttpResponseBadRequest(unicode(e)) if autograder: record_score = ExamRecordScore(record=record) record_score.save() feedback = {} total_score = 0 for prob, v in json_obj.iteritems( ): #prob is the "input" id, v is the associated value, #which can be an object (input box) or a list of objects (multiple-choice) try: if isinstance(v, list): #multiple choice case submission = map(lambda li: li['value'], v) feedback[prob] = autograder.grade(prob, submission) field_obj = ExamRecordScoreField( parent=record_score, field_name=prob, human_name=v[0].get('questionreport', "") if len(v) > 0 else "", subscore=feedback[prob]['score'], value=submission, correct=feedback[prob]['correct'], comments="", associated_text=v[0].get('associatedText', "") if len(v) > 0 else "", ) field_obj.save() for li in v: if 'correct_choices' not in feedback[prob]: is_correct = None else: is_correct = li['value'] in feedback[prob][ 'correct_choices'] fc = ExamRecordScoreFieldChoice( parent=field_obj, choice_value=li['value'], correct=is_correct, human_name=li.get('report', ""), associated_text=li.get('associatedText', "")) fc.save() else: #single answer submission = v['value'] feedback[prob] = autograder.grade(prob, submission) field_obj = ExamRecordScoreField( parent=record_score, field_name=prob, human_name=v.get('report', ""), subscore=feedback[prob]['score'], value=submission, correct=feedback[prob]['correct'], comments="", associated_text=v.get('associatedText', "")) field_obj.save() except AutoGraderGradingException as e: feedback[prob] = {'correct': False, 'score': 0} field_obj = ExamRecordScoreField( parent=record_score, field_name=prob, human_name=v.get('report', ""), subscore=0, correct=feedback[prob]['correct'], comments=unicode(e), associated_text=v.get('associatedText', "")) field_obj.save() #This is when using code indents to denote blocks is a bit hairy #supposed to be at the same level as try...except. Run once per prob,v total_score += feedback[prob]['score'] #Set raw score for ExamRecordScore record_score.raw_score = total_score record_score.save() #Set penalty inclusive score for ExamRecord record.json_score_data = json.dumps(feedback) #apply resubmission penalty resubmission_penalty_percent = pow( ((100 - exam.resubmission_penalty) / 100), (attempt_number - 1)) total_score = max(total_score * resubmission_penalty_percent, 0) #apply the late penalty if exam.grace_period and exam.late_penalty > 0 and datetime.datetime.now( ) > exam.grace_period: total_score = max(total_score * ((100 - exam.late_penalty) / 100), 0) record.score = total_score record.save() #Set ExamScore.score to max of ExamRecord.score for that student, exam. exam_score, created = ExamScore.objects.get_or_create(course=course, exam=exam, student=user) exam_score.setScore() return HttpResponse( reverse(exam.record_view, args=[course.prefix, course.suffix, exam.slug, record.id])) else: return HttpResponse("Submission has been saved.")