Esempio n. 1
0
def exam_feedback(request, course_prefix, course_suffix, exam_slug):
    """
    This is the endpoint that will be hit from an AJAX call from
    the front-end when the users pushes the "Check Answer" button
    on an interactive or in-video exercise.  For all problems
    submitted, do three things:

      1. instantiate and call the autograder
      2. write a log entry storing the attempt
      3. update the score table with the latest score

    While this will score and report results back for multiple
    problems, that isn't typical.
    """
    course = request.common_page_data['course']
    try:
        exam = Exam.objects.get(course = course, is_deleted=0, slug=exam_slug)
    except Exam.DoesNotExist:
        raise Http404

    submissions = json.loads(request.POST['json_data'])

    autograder = None
    if exam.autograde:
        try:
            autograder = AutoGrader(exam.xml_metadata)
        except Exception as e:
            return HttpResponseBadRequest(unicode(e))
    else:
        autograder = AutoGrader("<null></null>", default_return=True) #create a null autograder that always returns the "True" object
    if not autograder:
        return Http500("Could not create autograder")

    feedback = {}
    for prob, v in submissions.iteritems():
        if prob == "__metadata__":    # shouldn't happen, being careful
            next
        try:
            if isinstance(v,list):    # multiple choice case
                student_input = map(lambda li: li['value'], v)
                feedback[prob] = autograder.grade(prob, student_input)
            else:                     # single answer case
                student_input = v['value']
                feedback[prob] = autograder.grade(prob, student_input)
        except AutoGraderGradingException as e:
            logger.error(e)
            return HttpResponse(e, status=500)
        if 'questionreport' in v:
            human_name = v['questionreport']
        else:
            human_name = ""
        log_attempt(course, exam, request.user, student_input, human_name, prob, feedback[prob])
        update_score(course, exam, request.user, request.POST.get('json_data','{}'), prob, feedback[prob])

    feedback['__metadata__'] = exam.xml_metadata if exam.xml_metadata else "<empty></empty>"
    return HttpResponse(json.dumps(feedback))
Esempio n. 2
0
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))
Esempio n. 3
0
def collect_data(request, course_prefix, course_suffix, exam_slug):
    
    course = request.common_page_data['course']
    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)
    
    record = ExamRecord(course=course, exam=exam, student=request.user, json_data=postdata)
    record.save()

    if 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))

        feedback = {}
        for prob,v in json_obj.iteritems():
            try:
                if isinstance(v,list):
                    submission = map(lambda li: li['value'], v)
                    print(submission)
                    feedback[prob] = autograder.grade(prob, submission)
                else:
                    submission = float(v['value'])
                    print(submission)
                    feedback[prob] = autograder.grade(prob, submission)
            except ValueError:
                feedback[prob] = False
            except AutoGraderGradingException:
                pass
        return HttpResponse(json.dumps(feedback))

    else:
        return HttpResponse("Submission has been saved.")
Esempio n. 4
0
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.mode == "ready" and 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 = map(lambda li:li.encode('utf-8'),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.")
Esempio n. 5
0
def collect_data(request, course_prefix, course_suffix, exam_slug):
    
    course = request.common_page_data['course']
    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)
    
    record = ExamRecord(course=course, exam=exam, student=request.user, json_data=postdata)
    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():
            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('questiontag4humans', "") 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:
                        fc = ExamRecordScoreFieldChoice(parent=field_obj,
                                                        choice_value=li['value'],
                                                        human_name=li.get('tag4humans',""),
                                                        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('questiontag4humans', ""),
                                 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('questiontag4humans', ""),
                                 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']


        record_score.score = total_score
        record_score.save()
        record_score.copyToExamScore()         #Make this score the current ExamScore
        record.json_score_data = json.dumps(feedback)
        record.score = total_score
        record.save()

        return HttpResponse(json.dumps(feedback))

    else:
        return HttpResponse("Submission has been saved.")
Esempio n. 6
0
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)
Esempio n. 7
0
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.")