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