Пример #1
0
    def test_get_html_basic(self):
        """
        Some basic unit tests of randomizing question divs.
        """
        preamble = "<p>This is a <b>preamble</b></p>"
        question_template = \
"""
<div class="question" id="problem_%d">
    <p>Q1</p>
</div>
"""
        badxml1 = "<abc>"
        xml_none = "<exam_metadata />"
        xml_template = '<exam_metadata choosenquestions="%d" />'
        exam = Exam()

        #test with bad xml and xml_none, which should yield verbatim html
        for xml in [badxml1, xml_none]:
            exam.xml_metadata = xml
            for i in range(10):  #10 tests
                #build html with random number of questions
                j = random.randint(0, 10)
                html = preamble
                for k in range(j):
                    html += question_template % k
                exam.html_content = html
                self.assertEqual(exam.getHTML(), {
                    'html': html,
                    'subset': False,
                    'question_ids': []
                })

        #random test with good xml and good html.  these cases should result in a subset
        for i in range(10):  #10 tests
            n = random.randint(3, 10)  # number of actual questions
            exam.xml_metadata = xml_template % (
                n - 2)  #number of desired questions is n-2
            html = preamble
            for k in range(n):
                html += question_template % k
            exam.html_content = html
            result = exam.getHTML()
            self.assertTrue(result['subset'])
            self.assertEqual(len(result['question_ids']), n - 2)
            #parse out which random numbers were chosen
            chosen_nums = map(lambda id: int(id[-1]), result['question_ids'])
            #now reconstuct html to test equivalence
            reconstructed_html = preamble
            for num in chosen_nums:
                reconstructed_html += question_template % num
            self.assertEqual(re.sub(r"\s", "", result['html']),
                             re.sub(r"\s", "", reconstructed_html))

        #random test with good xml and good html with requesting more than we have.  these cases should not result in a subset
        for i in range(10):  #10 tests
            n = random.randint(3, 10)  # number of actual questions
            exam.xml_metadata = xml_template % (
                n + 2)  #number of desired questions is n+2
            html = preamble
            for k in range(n):
                html += question_template % k
            exam.html_content = html
            result = exam.getHTML()
            self.assertFalse(result['subset'])
            self.assertEqual(len(result['question_ids']), n)
            self.assertEqual(re.sub(r"\s", "", result['html']),
                             re.sub(r"\s", "", html))

        #test specifying question_ids
        for i in range(50):  #50 tests
            n = 10  #10 questions
            #setup the html
            html = preamble
            for k in range(n):
                html += question_template % k
            exam.html_content = html
            exam.xml_metadata = xml_template % 20  #to show that the choosenquestions attr doesn't matter in this case

            if i == 0:  #no removal here
                chosen_nums = range(n)
            else:
                m = random.randint(
                    0, 9
                )  # number of questions in question_ids, at most 9 so there will also be a removal
                t = range(2 * n)  #specify some qids that are not in the html
                chosen_nums = []
                while m != 0:
                    c = random.choice(t)
                    t.remove(c)
                    chosen_nums.append(c)
                    m -= 1

            chosen_ids = map(lambda n: "problem_%d" % n, chosen_nums)
            result = exam.getHTML(question_ids=chosen_ids)
            if i == 0:
                self.assertFalse(result['subset'])
            else:
                self.assertTrue(result['subset'])
            correct_chosen_nums = filter(lambda num: num < n, chosen_nums)
            correct_chosen_nums.sort()
            correct_chosen_ids = map(lambda n: "problem_%d" % n,
                                     correct_chosen_nums)
            self.assertEqual(correct_chosen_ids, result['question_ids'])
            #reconstruct html to test html output
            reconstructed_html = preamble
            for num in correct_chosen_nums:
                reconstructed_html += question_template % num
            self.assertEqual(re.sub(r"\s", "", result['html']),
                             re.sub(r"\s", "", reconstructed_html))
Пример #2
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','')
    
    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")

    #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()        

        # Set parent/child relationships
        create_contentgroup_entries_from_post(request, 'parent', exam_obj.image, 'exam', display_style='list')

        #Now set the video associations
        exam_obj.sync_videos_foreignkeys_with_metadata()
        vid_status_obj = exam_obj.image.sync_videos_foreignkeys_with_metadata()
        vid_status_string = ""
        if vid_status_obj['video_slugs_set']:
            exam_obj.invideo=True
            exam_obj.image.invideo=True
            exam_obj.save()
            exam_obj.image.save()
            vid_status_string = "This exam was successfully associated with the following videos:\n" + \
                            ", ".join(vid_status_obj['video_slugs_set']) + "\n"
        if vid_status_obj['video_slugs_not_set']:
            vid_status_string += "The following videos WERE NOT automatically associated with this exam:\n" + \
                ", ".join(vid_status_obj['video_slugs_not_set']) + "\n\n" + \
                "You may have provided the wrong url-identifier or have not yet uploaded the video"


        return HttpResponse("Exam " + title + " created. \n" + unicode(grader) + "\n\n" + vid_status_string)
    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()

            # Set parent/chlid relationships for this exam
            create_contentgroup_entries_from_post(request, 'parent', exam_obj.image, 'exam', display_style='list')

            #Now set the video associations
            exam_obj.sync_videos_foreignkeys_with_metadata()
            vid_status_obj = exam_obj.image.sync_videos_foreignkeys_with_metadata()
            vid_status_string = ""
            if vid_status_obj['video_slugs_set']:
                exam_obj.invideo=True
                exam_obj.image.invideo=True
                exam_obj.save()
                exam_obj.image.save()
                vid_status_string = "This exam was successfully associated with the following videos:\n" + \
                ", ".join(vid_status_obj['video_slugs_set']) + "\n\n"
            if vid_status_obj['video_slugs_not_set']:
                vid_status_string += "The following videos WERE NOT automatically associated with this exam:\n" + \
                    ", ".join(vid_status_obj['video_slugs_not_set']) + "\n" + \
                    "You may have provided the wrong url-identifier or have not yet uploaded the video"

            return HttpResponse("Exam " + title + " saved. \n" + unicode(grader) + "\n\n" + vid_status_string)

        except Exam.DoesNotExist:
            return HttpResponseBadRequest("No exam exists with URL identifier %s" % old_slug)
Пример #3
0
    def test_get_html_basic(self):
        """
        Some basic unit tests of randomizing question divs.
        """
        preamble = "<p>This is a <b>preamble</b></p>"
        question_template = \
"""
<div class="question" id="problem_%d">
    <p>Q1</p>
</div>
"""
        badxml1="<abc>"
        xml_none = "<exam_metadata />"
        xml_template = '<exam_metadata choosenquestions="%d" />'
        exam = Exam()

        #test with bad xml and xml_none, which should yield verbatim html
        for xml in [badxml1, xml_none]:
            exam.xml_metadata = xml
            for i in range(10): #10 tests
                #build html with random number of questions
                j = random.randint(0,10)
                html = preamble
                for k in range(j):
                    html += question_template % k
                exam.html_content = html
                self.assertEqual(exam.getHTML(), {'html':html, 'subset':False, 'question_ids':[]})

        #random test with good xml and good html.  these cases should result in a subset
        for i in range(10): #10 tests
            n = random.randint(3,10) # number of actual questions
            exam.xml_metadata = xml_template % (n-2) #number of desired questions is n-2
            html = preamble
            for k in range(n):
                html += question_template % k
            exam.html_content = html
            result = exam.getHTML()
            self.assertTrue(result['subset'])
            self.assertEqual(len(result['question_ids']), n-2)
            #parse out which random numbers were chosen
            chosen_nums = map(lambda id: int(id[-1]), result['question_ids'])
            #now reconstuct html to test equivalence
            reconstructed_html = preamble
            for num in chosen_nums:
                reconstructed_html += question_template % num
            self.assertEqual(re.sub(r"\s","", result['html']), re.sub(r"\s","", reconstructed_html))

        #random test with good xml and good html with requesting more than we have.  these cases should not result in a subset
        for i in range(10): #10 tests
            n = random.randint(3,10) # number of actual questions
            exam.xml_metadata = xml_template % (n+2) #number of desired questions is n+2
            html = preamble
            for k in range(n):
                html += question_template % k
            exam.html_content = html
            result = exam.getHTML()
            self.assertFalse(result['subset'])
            self.assertEqual(len(result['question_ids']), n)
            self.assertEqual(re.sub(r"\s","", result['html']), re.sub(r"\s","", html))

        #test specifying question_ids
        for i in range(50): #50 tests
            n = 10 #10 questions
            #setup the html
            html = preamble
            for k in range(n):
                html += question_template % k
            exam.html_content = html
            exam.xml_metadata = xml_template % 20 #to show that the choosenquestions attr doesn't matter in this case
            
            if i==0: #no removal here
                chosen_nums = range(n)
            else:
                m = random.randint(0,9) # number of questions in question_ids, at most 9 so there will also be a removal
                t = range(2*n) #specify some qids that are not in the html
                chosen_nums = []
                while m != 0:
                    c = random.choice(t)
                    t.remove(c)
                    chosen_nums.append(c)
                    m -= 1

            chosen_ids = map(lambda n: "problem_%d" % n, chosen_nums)
            result = exam.getHTML(question_ids=chosen_ids)
            if i==0:
                self.assertFalse(result['subset'])
            else:
                self.assertTrue(result['subset'])
            correct_chosen_nums = filter(lambda num: num < n, chosen_nums)
            correct_chosen_nums.sort()
            correct_chosen_ids = map(lambda n: "problem_%d" % n, correct_chosen_nums)
            self.assertEqual(correct_chosen_ids, result['question_ids'])
            #reconstruct html to test html output
            reconstructed_html = preamble
            for num in correct_chosen_nums:
                reconstructed_html += question_template % num
            self.assertEqual(re.sub(r"\s","", result['html']), re.sub(r"\s","", reconstructed_html))
Пример #4
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)
Пример #5
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)