Exemple #1
0
def view(request, course_prefix, course_suffix, slug):

    common_page_data = request.common_page_data
    
    try:
        #getByCourse takes care of checking for draft vs live, is_deleted and live times
        video = Video.objects.getByCourse(course=common_page_data['course']).get(slug=slug)
    except Video.DoesNotExist:
        raise Http404
    
    if not common_page_data['is_course_admin']:
        visit_log = PageVisitLog(
            course = common_page_data['ready_course'],
            user = request.user,
            page_type= 'video',
            object_id = str(video.id),
        )
        visit_log.save()

    if not 'video_quiz_mode' in request.session:
        #Default to include quizzes in viewing videos
        request.session['video_quiz_mode'] = "quizzes included"

    videos = Video.objects.getByCourse(course=common_page_data['course'])
    #Get index of current video
    cur_index = None #just code safety
    for index, item in enumerate(videos):
        if item == video:
            cur_index = index
            break

    ready_section = video.section
    if ready_section and ready_section.mode == "draft":
        ready_section = ready_section.image

    #code safety
    next_slug = None
    prev_slug = None

    if cur_index is not None:
        if cur_index > 0:
            prev_slug = videos[cur_index-1].slug
        else:
            prev_slug = None
        if cur_index < videos.count() - 1:
            next_slug = videos[cur_index+1].slug
        else:
            next_slug = None

    video_rec = request.user.videoactivity_set.filter(video=video)
    if video_rec:
        video_rec = video_rec[0]
    else:
        #note student field to be renamed to user, VideoActivity for all users now
        video_rec = VideoActivity(student=request.user, course=common_page_data['course'], video=video)
        video_rec.save()
        
    course = common_page_data['course']

    key = ('video', video.id)
    l1items, l2items = get_contentgroup_data(course=course)
    downloadable_content = get_children(key, l1items, l2items)

    if video.exam:
        try:
            exam = video.exam
            video_obj = videos_in_exam_metadata(exam.xml_metadata, times_for_video_slug=video.slug)
            question_times = video_obj['question_times']

        except Exam.DoesNotExist:
            raise Http404
    else:
        sections = ContentSection.objects.getByCourse(course) 
        section = sections[0]
        # create fake exam as exam template (which is what displays all videos) needs exam data to function
        # correctly (TODO: Refactor this)
        exam = Exam(course=course, slug=slug, title=video.title, description="Empty Exam", html_content="", xml_metadata="", due_date='', assessment_type="survey", mode="draft", total_score=0, grade_single=0, grace_period='', partial_credit_deadline='', late_penalty=0, submissions_permitted=0, resubmission_penalty=0, exam_type="survey", autograde=0, display_single=0, invideo=1, section=section,)
        exam.live_datetime = video.live_datetime    # needed so video shows up
        question_times = ""

    return render_to_response('exams/view_exam.html', 
                              {
                               'common_page_data':    common_page_data, 
                               'video':               video,
                               'ready_section':       ready_section,
                               'video_rec':           video_rec, 
                               'prev_slug':           prev_slug, 
                               'next_slug':           next_slug, 
                               'downloadable_content':downloadable_content,
                               'json_pre_pop':"{}",
                               'scores':"{}",
                               'editable':True,
                               'single_question':exam.display_single,
                               'videotest':exam.invideo,
                               'question_times':json.dumps(question_times),
                               'allow_submit':True,
                               'children': downloadable_content,
                               'exam':exam
                              },
                              context_instance=RequestContext(request))
Exemple #2
0
    def test_num_questions(self):
        """
        Tests the num_questions function in the Exam() class.
        """
        badxml1 = "<"
        badxml2 = "<abc>"
        badxml3 = "<def />"
        badxml4 = """<exam_metadata choosenquestions="" />"""
        badxml5 = """<exam_metadata choosenquestions="baby" />"""
        xml1 = "<exam_metadata />"
        xml2 = """<exam_metadata choosenquestions="3" />"""
        xml3 = """<exam_metadata choosenquestions="542" />"""

        exam = Exam()
        exam.xml_metadata = badxml1
        self.assertEqual(exam.num_random_questions(), 0)
        exam.xml_metadata = badxml2
        self.assertEqual(exam.num_random_questions(), 0)
        exam.xml_metadata = badxml3
        self.assertEqual(exam.num_random_questions(), 0)
        exam.xml_metadata = badxml4
        self.assertEqual(exam.num_random_questions(), 0)
        exam.xml_metadata = badxml5
        self.assertEqual(exam.num_random_questions(), 0)
        exam.xml_metadata = xml1
        self.assertEqual(exam.num_random_questions(), 0)
        exam.xml_metadata = xml2
        self.assertEqual(exam.num_random_questions(), 3)
        exam.xml_metadata = xml3
        self.assertEqual(exam.num_random_questions(), 542)
Exemple #3
0
def view(request, course_prefix, course_suffix, slug):

    common_page_data = request.common_page_data
    
    try:
        #getByCourse takes care of checking for draft vs live, is_deleted and live times
        video = Video.objects.getByCourse(course=common_page_data['course']).get(slug=slug)
    except Video.DoesNotExist:
        raise Http404
    
    if not common_page_data['is_course_admin']:
        visit_log = PageVisitLog(
            course = common_page_data['ready_course'],
            user = request.user,
            page_type= 'video',
            object_id = str(video.id),
        )
        visit_log.save()

    if not 'video_quiz_mode' in request.session:
        #Default to include quizzes in viewing videos
        request.session['video_quiz_mode'] = "quizzes included"

    videos = Video.objects.getByCourse(course=common_page_data['course'])
    #Get index of current video
    cur_index = None #just code safety
    for index, item in enumerate(videos):
        if item == video:
            cur_index = index
            break

    #code safety
    next_slug = None
    prev_slug = None

    if cur_index is not None:
        if cur_index > 0:
            prev_slug = videos[cur_index-1].slug
        else:
            prev_slug = None
        if cur_index < videos.count() - 1:
            next_slug = videos[cur_index+1].slug
        else:
            next_slug = None

    video_rec = request.user.videoactivity_set.filter(video=video)
    if video_rec:
        video_rec = video_rec[0]
    else:
        #note student field to be renamed to user, VideoActivity for all users now
        video_rec = VideoActivity(student=request.user, course=common_page_data['course'], video=video)
        video_rec.save()
        
    course = common_page_data['course']
    full_contentsection_list, full_index_list = get_full_contentsection_list(course, filter_children=True)

    if request.user.is_authenticated():
        is_logged_in = 1
    else:
        is_logged_in = 0    

    key = ('video', video.id)
    l1items, l2items = get_contentgroup_data(course=course)
    downloadable_content = get_children(key, l1items, l2items)

    if video.exam:
        try:
            #exam = Exam.objects.get(course=course, is_deleted=0, slug=exam_slug)
            exam = video.exam
            display_single = exam.display_single
            invideo = exam.invideo
            metadata_dom = parseString(exam.xml_metadata) #The DOM corresponding to the XML metadata
            video_questions = metadata_dom.getElementsByTagName('video')
           
            question_times = {}
            for video_node in video_questions:
                video_slug = video_node.getAttribute("url-identifier")
                if video_slug == "":
                    video_slug = video_node.getAttribute("url_identifier")
                if video_slug == video.slug:
                    question_children = video_node.getElementsByTagName("question")
                    times = []
                    for question in question_children:
                        time = "sec_%s" % question.getAttribute("time")
                        if time not in question_times:
                            question_times[time] = [] 
                        question_times[time].append(question.getAttribute("id"))

            print json.dumps(question_times)

        except Exam.DoesNotExist:
            raise Http404
    else:
        sections = ContentSection.objects.getByCourse(course) 
        section = sections[0]
        # create fake exam as exam template (which is what displays all videos) needs exam data to function
        # correctly (TODO: Refactor this)
        exam = Exam(course=course, slug=slug, title=video.title, description="Empty Exam", html_content="", xml_metadata="", due_date='', assessment_type="survey", mode="draft", total_score=0, grade_single=0, grace_period='', partial_credit_deadline='', late_penalty=0, submissions_permitted=0, resubmission_penalty=0, exam_type="survey", autograde=0, display_single=0, invideo=1, section=section,)
        exam.live_datetime = video.live_datetime    # needed so video shows up
        question_times = ""

    videoURL = None
    thumbnailPath = None
    
    if is_storage_local():
        videoURL = local_file_server_root() + "/" + str(video.file)
        thumbnailPath = local_file_server_root() + "/" + course.prefix + "/" + course.suffix + "/videos/" + str(video.id if video.mode == 'draft' else video.image.id) + "/jpegs/"
    elif video.url:
        videoURL = "http://www.youtube.com/embed/" + (video.url if video.mode == 'draft' else video.image.url) + "?autoplay=0&wmode=transparent&fs=0&rel=0&modestbranding=1&showinfo=0&start=0&enablejsapi=1&disablekb=1&amp;"
        thumbnailPath = "http://" + settings.AWS_STORAGE_BUCKET_NAME + ".s3-website-us-west-2.amazonaws.com/" + course.prefix + "/" + course.suffix + "/videos/" + str(video.id if video.mode == 'draft' else video.image.id) + "/jpegs/"


    # change from 'videos/view.html' to 'exams/view_exam.html'
    return render_to_response('exams/view_exam.html', 
                              {
                               'common_page_data':    common_page_data, 
                               'video':               video, 
                               'video_rec':           video_rec,
                               'videoURL':            videoURL,
                               'thumbnailPath':       thumbnailPath,
                               'prev_slug':           prev_slug, 
                               'next_slug':           next_slug, 
                               'contentsection_list': full_contentsection_list, 
                               'full_index_list':     full_index_list,
                               'is_logged_in':        is_logged_in,
                               'downloadable_content':downloadable_content,
                               'json_pre_pop':"{}",
                               'scores':"{}",
                               'editable':True,
                               'single_question':exam.display_single,
                               'videotest':exam.invideo,
                               'question_times':json.dumps(question_times),
                               'allow_submit':True,
                               'children': downloadable_content,
                               'exam':exam
                              },
                              context_instance=RequestContext(request))
Exemple #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','')
    
    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)
Exemple #5
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))
Exemple #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)
Exemple #7
0
def view(request, course_prefix, course_suffix, slug):

    common_page_data = request.common_page_data

    try:
        # getByCourse takes care of checking for draft vs live, is_deleted and live times
        video = Video.objects.getByCourse(course=common_page_data["course"]).get(slug=slug)
    except Video.DoesNotExist:
        raise Http404

    if not common_page_data["is_course_admin"]:
        visit_log = PageVisitLog(
            course=common_page_data["ready_course"], user=request.user, page_type="video", object_id=str(video.id)
        )
        visit_log.save()

    if not "video_quiz_mode" in request.session:
        # Default to include quizzes in viewing videos
        request.session["video_quiz_mode"] = "quizzes included"

    videos = Video.objects.getByCourse(course=common_page_data["course"])
    # Get index of current video
    cur_index = None  # just code safety
    for index, item in enumerate(videos):
        if item == video:
            cur_index = index
            break

    # code safety
    next_slug = None
    prev_slug = None

    if cur_index is not None:
        if cur_index > 0:
            prev_slug = videos[cur_index - 1].slug
        else:
            prev_slug = None
        if cur_index < videos.count() - 1:
            next_slug = videos[cur_index + 1].slug
        else:
            next_slug = None

    video_rec = request.user.videoactivity_set.filter(video=video)
    if video_rec:
        video_rec = video_rec[0]
    else:
        # note student field to be renamed to user, VideoActivity for all users now
        video_rec = VideoActivity(student=request.user, course=common_page_data["course"], video=video)
        video_rec.save()

    course = common_page_data["course"]
    full_contentsection_list, full_index_list = get_full_contentsection_list(course, filter_children=True)

    if request.user.is_authenticated():
        is_logged_in = 1
    else:
        is_logged_in = 0

    key = ("video", video.id)
    l1items, l2items = get_contentgroup_data(course=course)
    downloadable_content = get_children(key, l1items, l2items)

    if video.exam:
        try:
            # exam = Exam.objects.get(course=course, is_deleted=0, slug=exam_slug)
            exam = video.exam
            display_single = exam.display_single
            invideo = exam.invideo
            metadata_dom = parseString(exam.xml_metadata)  # The DOM corresponding to the XML metadata
            video_questions = metadata_dom.getElementsByTagName("video")

            question_times = {}
            for video_node in video_questions:
                video_slug = video_node.getAttribute("url-identifier")
                if video_slug == "":
                    video_slug = video_node.getAttribute("url_identifier")
                if video_slug == video.slug:
                    question_children = video_node.getElementsByTagName("question")
                    times = []
                    for question in question_children:
                        time = "sec_%s" % question.getAttribute("time")
                        if time not in question_times:
                            question_times[time] = []
                        question_times[time].append(question.getAttribute("id"))

            print json.dumps(question_times)

        except Exam.DoesNotExist:
            raise Http404
    else:
        sections = ContentSection.objects.getByCourse(course)
        section = sections[0]
        # create fake exam as exam template (which is what displays all videos) needs exam data to function
        # correctly (TODO: Refactor this)
        exam = Exam(
            course=course,
            slug=slug,
            title=video.title,
            description="Empty Exam",
            html_content="",
            xml_metadata="",
            due_date="",
            assessment_type="survey",
            mode="draft",
            total_score=0,
            grade_single=0,
            grace_period="",
            partial_credit_deadline="",
            late_penalty=0,
            submissions_permitted=0,
            resubmission_penalty=0,
            exam_type="survey",
            autograde=0,
            display_single=0,
            invideo=1,
            section=section,
        )
        exam.live_datetime = video.live_datetime  # needed so video shows up
        question_times = ""

    # change from 'videos/view.html' to 'exams/view_exam.html'
    return render_to_response(
        "exams/view_exam.html",
        {
            "common_page_data": common_page_data,
            "video": video,
            "video_rec": video_rec,
            "prev_slug": prev_slug,
            "next_slug": next_slug,
            "contentsection_list": full_contentsection_list,
            "full_index_list": full_index_list,
            "is_logged_in": is_logged_in,
            "downloadable_content": downloadable_content,
            "json_pre_pop": "{}",
            "scores": "{}",
            "editable": True,
            "single_question": exam.display_single,
            "videotest": exam.invideo,
            "question_times": json.dumps(question_times),
            "allow_submit": True,
            "children": downloadable_content,
            "exam": exam,
        },
        context_instance=RequestContext(request),
    )
Exemple #8
0
    def test_num_questions(self):
        """
        Tests the num_questions function in the Exam() class.
        """
        badxml1="<"
        badxml2="<abc>"
        badxml3="<def />"
        badxml4="""<exam_metadata choosenquestions="" />"""
        badxml5="""<exam_metadata choosenquestions="baby" />"""
        xml1="<exam_metadata />"
        xml2="""<exam_metadata choosenquestions="3" />"""
        xml3="""<exam_metadata choosenquestions="542" />"""

        exam = Exam()
        exam.xml_metadata=badxml1
        self.assertEqual(exam.num_random_questions(),0)
        exam.xml_metadata=badxml2
        self.assertEqual(exam.num_random_questions(),0)
        exam.xml_metadata=badxml3
        self.assertEqual(exam.num_random_questions(),0)
        exam.xml_metadata=badxml4
        self.assertEqual(exam.num_random_questions(),0)
        exam.xml_metadata=badxml5
        self.assertEqual(exam.num_random_questions(),0)
        exam.xml_metadata=xml1
        self.assertEqual(exam.num_random_questions(),0)
        exam.xml_metadata=xml2
        self.assertEqual(exam.num_random_questions(),3)
        exam.xml_metadata=xml3
        self.assertEqual(exam.num_random_questions(),542)
Exemple #9
0
def view(request, course_prefix, course_suffix, slug):

    common_page_data = request.common_page_data

    try:
        #getByCourse takes care of checking for draft vs live, is_deleted and live times
        video = Video.objects.getByCourse(
            course=common_page_data['course']).get(slug=slug)
    except Video.DoesNotExist:
        raise Http404

    if not common_page_data['is_course_admin']:
        visit_log = PageVisitLog(
            course=common_page_data['ready_course'],
            user=request.user,
            page_type='video',
            object_id=str(video.id),
        )
        visit_log.save()

    if not 'video_quiz_mode' in request.session:
        #Default to include quizzes in viewing videos
        request.session['video_quiz_mode'] = "quizzes included"

    videos = Video.objects.getByCourse(course=common_page_data['course'])
    #Get index of current video
    cur_index = None  #just code safety
    for index, item in enumerate(videos):
        if item == video:
            cur_index = index
            break

    #code safety
    next_slug = None
    prev_slug = None

    if cur_index is not None:
        if cur_index > 0:
            prev_slug = videos[cur_index - 1].slug
        else:
            prev_slug = None
        if cur_index < videos.count() - 1:
            next_slug = videos[cur_index + 1].slug
        else:
            next_slug = None

    video_rec = request.user.videoactivity_set.filter(video=video)
    if video_rec:
        video_rec = video_rec[0]
    else:
        #note student field to be renamed to user, VideoActivity for all users now
        video_rec = VideoActivity(student=request.user,
                                  course=common_page_data['course'],
                                  video=video)
        video_rec.save()

    course = common_page_data['course']
    full_contentsection_list, full_index_list = get_full_contentsection_list(
        course, filter_children=True)

    if request.user.is_authenticated():
        is_logged_in = 1
    else:
        is_logged_in = 0

    key = ('video', video.id)
    l1items, l2items = get_contentgroup_data(course=course)
    downloadable_content = get_children(key, l1items, l2items)

    if video.exam:
        try:
            #exam = Exam.objects.get(course=course, is_deleted=0, slug=exam_slug)
            exam = video.exam
            display_single = exam.display_single
            invideo = exam.invideo
            metadata_dom = parseString(
                exam.xml_metadata)  #The DOM corresponding to the XML metadata
            video_questions = metadata_dom.getElementsByTagName('video')

            question_times = {}
            for video_node in video_questions:
                video_slug = video_node.getAttribute("url-identifier")
                if video_slug == "":
                    video_slug = video_node.getAttribute("url_identifier")
                if video_slug == video.slug:
                    question_children = video_node.getElementsByTagName(
                        "question")
                    times = []
                    for question in question_children:
                        time = "sec_%s" % question.getAttribute("time")
                        if time not in question_times:
                            question_times[time] = []
                        question_times[time].append(
                            question.getAttribute("id"))

            print json.dumps(question_times)

        except Exam.DoesNotExist:
            raise Http404
    else:
        sections = ContentSection.objects.getByCourse(course)
        section = sections[0]
        # create fake exam as exam template (which is what displays all videos) needs exam data to function
        # correctly (TODO: Refactor this)
        exam = Exam(
            course=course,
            slug=slug,
            title=video.title,
            description="Empty Exam",
            html_content="",
            xml_metadata="",
            due_date='',
            assessment_type="survey",
            mode="draft",
            total_score=0,
            grade_single=0,
            grace_period='',
            partial_credit_deadline='',
            late_penalty=0,
            submissions_permitted=0,
            resubmission_penalty=0,
            exam_type="survey",
            autograde=0,
            display_single=0,
            invideo=1,
            section=section,
        )
        exam.live_datetime = video.live_datetime  # needed so video shows up
        question_times = ""

    videoURL = None
    thumbnailPath = None

    if is_storage_local():
        videoURL = local_file_server_root() + "/" + str(video.file)
        thumbnailPath = local_file_server_root(
        ) + "/" + course.prefix + "/" + course.suffix + "/videos/" + str(
            video.id if video.mode == 'draft' else video.image.id) + "/jpegs/"
    elif video.url:
        videoURL = "http://www.youtube.com/embed/" + (
            video.url if video.mode == 'draft' else video.image.url
        ) + "?autoplay=0&wmode=transparent&fs=0&rel=0&modestbranding=1&showinfo=0&start=0&enablejsapi=1&disablekb=1&amp;"
        thumbnailPath = "http://" + settings.AWS_STORAGE_BUCKET_NAME + ".s3-website-us-west-2.amazonaws.com/" + course.prefix + "/" + course.suffix + "/videos/" + str(
            video.id if video.mode == 'draft' else video.image.id) + "/jpegs/"

    # change from 'videos/view.html' to 'exams/view_exam.html'
    return render_to_response('exams/view_exam.html', {
        'common_page_data': common_page_data,
        'video': video,
        'video_rec': video_rec,
        'videoURL': videoURL,
        'thumbnailPath': thumbnailPath,
        'prev_slug': prev_slug,
        'next_slug': next_slug,
        'contentsection_list': full_contentsection_list,
        'full_index_list': full_index_list,
        'is_logged_in': is_logged_in,
        'downloadable_content': downloadable_content,
        'json_pre_pop': "{}",
        'scores': "{}",
        'editable': True,
        'single_question': exam.display_single,
        'videotest': exam.invideo,
        'question_times': json.dumps(question_times),
        'allow_submit': True,
        'children': downloadable_content,
        'exam': exam
    },
                              context_instance=RequestContext(request))
Exemple #10
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))
Exemple #11
0
def save_exam_ajax(request, course_prefix, course_suffix):
    course = request.common_page_data['course']
    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', '')
    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','')
    
    #########Validation, lots of validation#######
    if not slug:
        return HttpResponseBadRequest("No URL identifier value provided")
    if Exam.objects.filter(course=course, slug=slug).exists():
        return HttpResponseBadRequest("An exam with this URL identifier already exists in this course")
    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))

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

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

    print(assessment_type)
    if assessment_type == "summative":
        autograde = True
        invideo = False
        display_single = False
        exam_type = "exam"
    elif assessment_type == "invideo":
        autograde = True
        invideo = True
        display_single = True
        exam_type = "exam"
    elif assessment_type == "exam-autograde":
        autograde = True
        invideo = False
        display_single = False
        exam_type = "exam"
    elif assessment_type == "exam-csv":
        autograde = False
        invideo = False
        display_single = False
        exam_type = "exam"
    elif assessment_type == "survey":
        autograde = False
        invideo = False
        display_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(late_penalty)
        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 Exam
    exam_obj = Exam(course=course, slug=slug, title=title, description=description, html_content=htmlContent, xml_metadata=metaXMLContent, due_date=dd,
                    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)
    exam_obj.save()

    return HttpResponse("Exam " + title + " created")
Exemple #12
0
def view(request, course_prefix, course_suffix, slug):

    common_page_data = request.common_page_data

    try:
        #getByCourse takes care of checking for draft vs live, is_deleted and live times
        video = Video.objects.getByCourse(
            course=common_page_data['course']).get(slug=slug)
    except Video.DoesNotExist:
        raise Http404

    if not common_page_data['is_course_admin']:
        visit_log = PageVisitLog(
            course=common_page_data['ready_course'],
            user=request.user,
            page_type='video',
            object_id=str(video.id),
        )
        visit_log.save()

    if not 'video_quiz_mode' in request.session:
        #Default to include quizzes in viewing videos
        request.session['video_quiz_mode'] = "quizzes included"

    videos = Video.objects.getByCourse(course=common_page_data['course'])
    #Get index of current video
    cur_index = None  #just code safety
    for index, item in enumerate(videos):
        if item == video:
            cur_index = index
            break

    ready_section = video.section
    if ready_section and ready_section.mode == "draft":
        ready_section = ready_section.image

    #code safety
    next_slug = None
    prev_slug = None

    if cur_index is not None:
        if cur_index > 0:
            prev_slug = videos[cur_index - 1].slug
        else:
            prev_slug = None
        if cur_index < videos.count() - 1:
            next_slug = videos[cur_index + 1].slug
        else:
            next_slug = None

    video_rec = request.user.videoactivity_set.filter(video=video)
    if video_rec:
        video_rec = video_rec[0]
    else:
        #note student field to be renamed to user, VideoActivity for all users now
        video_rec = VideoActivity(student=request.user,
                                  course=common_page_data['course'],
                                  video=video)
        video_rec.save()

    course = common_page_data['course']

    key = ('video', video.id)
    l1items, l2items = get_contentgroup_data(course=course)
    downloadable_content = get_children(key, l1items, l2items)

    if video.exam:
        try:
            exam = video.exam
            video_obj = videos_in_exam_metadata(
                exam.xml_metadata, times_for_video_slug=video.slug)
            question_times = video_obj['question_times']

        except Exam.DoesNotExist:
            raise Http404
    else:
        sections = ContentSection.objects.getByCourse(course)
        section = sections[0]
        # create fake exam as exam template (which is what displays all videos) needs exam data to function
        # correctly (TODO: Refactor this)
        exam = Exam(
            course=course,
            slug=slug,
            title=video.title,
            description="Empty Exam",
            html_content="",
            xml_metadata="",
            due_date='',
            assessment_type="survey",
            mode="draft",
            total_score=0,
            grade_single=0,
            grace_period='',
            partial_credit_deadline='',
            late_penalty=0,
            submissions_permitted=0,
            resubmission_penalty=0,
            exam_type="survey",
            autograde=0,
            display_single=0,
            invideo=1,
            section=section,
        )
        exam.live_datetime = video.live_datetime  # needed so video shows up
        question_times = ""

    return render_to_response('exams/view_exam.html', {
        'common_page_data': common_page_data,
        'video': video,
        'ready_section': ready_section,
        'video_rec': video_rec,
        'prev_slug': prev_slug,
        'next_slug': next_slug,
        'downloadable_content': downloadable_content,
        'json_pre_pop': "{}",
        'scores': "{}",
        'editable': True,
        'single_question': exam.display_single,
        'videotest': exam.invideo,
        'question_times': json.dumps(question_times),
        'allow_submit': True,
        'children': downloadable_content,
        'exam': exam,
    },
                              context_instance=RequestContext(request))
Exemple #13
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)
Exemple #14
0
class Command(BaseCommand):
    """
    Define the edit_exam manamagement command: bulk updates of exam settings.
    """

    # instantiate a dummy exam so we can inspect it
    testexam=Exam()
    exam_attrs = [a for a in vars(testexam) \
                    if not callable(getattr(testexam,a)) \
                    and not a.startswith('_')]
    exam_types = [t[0] for t in Exam.EXAM_TYPE_CHOICES]

    help = "Make bulk exam changes. With the -u option update the database. " \
            " PLEASE BE CAREFUL." \
            "\n\nSelect which exams to change with one or more of " \
            "-e, -c, and -t. At least one of -e or -c must be used." \
            "\n\nThe list of Exam columns are:\n%s" % "\n".join(wrap(", ".join(sorted(exam_attrs))))

    option_list = (
        # Select
        make_option("-e", "--examids", dest="exam_ids", type="string",
            help="Select by comma-separated list of exam ID's"),
        make_option("-c", "--courseid", dest="course_id", type="int", 
            help="Select by course.  If only this option is chosen, all exams " \
                    "for that course will be selected."),
        make_option("-t", "--type", dest="examtype", type="string",
            help="Select by type, valid values are: %s" \
                    % ", ".join(sorted(exam_types))),

        # Change
        make_option("-s", "--set", action="append", dest="setlist", 
            default=[], metavar="NAME=\"VAL\"",
            help="Set this to that for every exam that matches your search. "  \
                 "Specify this multiple times to update multiple columns. " \
                 "The quotes around the value are optional."),

        # Do It!
        make_option("-u", "--update", action="store_false", dest="dryrun", default=True,
            help="actually update database (default is dry run)."),

    ) + BaseCommand.option_list


    def validate_selector(self, options):
        """
        Make sure we have a valid set of things to select on, and if we do,
        return a named tuple like this:
          Selector(exam_ids=[840, 841], course_id=11, type='survey')
        """
        if not (options['exam_ids'] or options['course_id']):
            raise CommandError("At least one of exam_ids (-e) or course_id (-c) is required.")

        Selector = namedtuple('Selector', 'exam_ids, course_id, examtype')

        result_exam_id_list = []
        if options['exam_ids']:
            exid_strings = options['exam_ids'].split(',')
            for exid_str in exid_strings:
                errstr = None
                try:
                    exid = int(exid_str)
                    if exid == 0:
                        errstr = "exam id \"%s\" is invalid"
                except ValueError as e:
                    errstr = e
                if errstr:
                    raiseCommandError("Exam ID parsing error, %s" % errstr)
                result_exam_id_list.append(exid)

        if options['examtype']:
            if options['examtype'] not in self.exam_types:
                raise CommandError("Invalid exam type \"%s\" given, allowed types are: %s"
                    % (options['examtype'], ", ".join(sorted(self.exam_types))))

        return Selector(exam_ids=result_exam_id_list, 
                course_id=options['course_id'], 
                examtype=options['examtype'])


    def validate_setters(self, options):
        """
        Decide what we're going to set for each of the exams we select.  Returns
        a dict with columns and settings for each.
        """
        resultdict = {}

        if not options['setlist']:
            raise CommandError("you must specify at least one set (-s) command")

        for cmd in options['setlist']:
            splitcmd = cmd.split('=')
            if len(splitcmd) != 2:
                raise CommandError("cannot parse \"%s\", commands must be of the form NAME=VAL"
                        % cmd)
            (name, val) = splitcmd
            if name not in self.exam_attrs:
                raise CommandError("value \"%s\" isn't a valid property of Exam, valid values are %s"
                        % (splitcmd[0], self.exam_attrs))
            resultdict[name] = val

        return resultdict


    def handle(self, *args, **options):
        """The actual exam_edit command"""

        selector = self.validate_selector(options)
        pprint(selector)

        setter_dict = self.validate_setters(options)
        sys.stdout.write("Setters = ")
        pprint(setter_dict)
                
        exams = Exam.objects.all()
        if selector.course_id:
            exams = exams.filter(course=selector.course_id)
        if selector.exam_ids:
            exams = exams.filter(id__in=selector.exam_ids)
        if selector.examtype:
            exams = exams.filter(exam_type=selector.examtype)

        if options['dryrun']:
            matches = len(exams)
            print "dryrun matches = %d" % matches
        else:
            updates = exams.update(**setter_dict)
            print "updated = %d" % updates

        for exam in exams:
            sys.stdout.write("%d: " % exam.id)
            pprint(exam)