Ejemplo n.º 1
0
def _render_question(question, rng, seed, context):


    questions_rendered = context.get('_questions_rendered',0)
    questions_rendered += 1
    context['_questions_rendered'] = questions_rendered

    # use qtag in identifier since coming from tag
    identifier = "qtag_%s" % questions_rendered
    
    try:
        auxiliary_data=context['_auxiliary_data_']
    except KeyError:
        from midocs.functions import return_new_auxiliary_data
        auxiliary_data =  return_new_auxiliary_data()
        context['_auxiliary_data_'] = auxiliary_data


    question_dict= {'question': question, 'seed': seed}
    question_data = render_question(question_dict, 
                                    question_identifier=identifier,
                                    auxiliary_data=auxiliary_data,
                                    rng=rng)
    
    html_string = template.loader.render_to_string("mitesting/question_body.html",
                                                   {'question_data': question_data})
    
    
    html_string = '<div class="question">%s</div>' % html_string

    return html_string
Ejemplo n.º 2
0
def appletview_bare(request, applet_code):
    theapplet = get_object_or_404(Applet, code=applet_code)
    
    width=request.GET.get("width")
    height=request.GET.get("height")
    applet_identifier=request.GET.get("applet_identifier")

    from midocs.functions import return_new_auxiliary_data
    auxiliary_data = return_new_auxiliary_data()

    return render(request, "midocs/applet_bare.html", 
                  {'applet': theapplet, 
                   '_auxiliary_data_': auxiliary_data,
                'width': width, 'height': height,
                   'applet_identifier': applet_identifier,
               })
Ejemplo n.º 3
0
    def get_context_data(self, **kwargs):
        context = super(QuestionView, self).get_context_data(**kwargs)
        
        try:
            seed = self.request.GET['seed']
        except:
            seed = None

        # show help if not rendering solution
        show_help = not self.solution
        
        # In question view, there will be only one question on page.
        # Identifier doesn't matter.  Use qv to indiciate from question view.
        identifier = "qv"

        from midocs.functions import return_new_auxiliary_data
        auxiliary_data =  return_new_auxiliary_data()

        import random
        rng = random.Random()

        question_dict={'question': self.object,
                       'seed': seed,}
        from mitesting.render_questions import render_question
        context['question_data']= render_question(
            question_dict=question_dict,
            rng=rng,  user=self.request.user,
            question_identifier=identifier, 
            allow_solution_buttons=True,
            solution=self.solution,
            show_help = show_help,
            auxiliary_data=auxiliary_data,
            show_post_user_errors=True)

        context['_auxiliary_data_'] = auxiliary_data

        context['show_lists']=True

        # no Google analytics for questions
        context['noanalytics']=True

        return context
Ejemplo n.º 4
0
def process_expressions_from_answers(question):

    # update expression from answers from question text and subparts
    # update dynamic text from question and solution text and subparts

    # just assume every answer code is valid 
    valid_answer_codes = {}
    for ao in question.questionansweroption_set.all():
        answer_dict = {'answer_type': ao.answer_type,
                       'split_symbols_on_compare':
                       ao.split_symbols_on_compare
        }
        valid_answer_codes[ao.answer_code]=answer_dict


    import random
    rng=random.Random()

    answer_data = return_new_answer_data(rng)
    answer_data['valid_answer_codes'] = valid_answer_codes
    answer_data['question']=question

    from midocs.functions import return_new_auxiliary_data
    auxiliary_data =  return_new_auxiliary_data()

    update_context = Context({'question': question, 
                              '_process_dynamictext': True,
                              '_dynamictext_object': question,
                              '_process_expressions_from_answers': True,
                              '_answer_data_': answer_data,
                              '_sympy_local_dict_': {},
                              '_auxiliary_data_': auxiliary_data,
                          })


    from dynamictext.models import DynamicText
    DynamicText.initialize(question)
    question.expressionfromanswer_set.all().delete()
    render_results=render_question_text(
        {'question': question, 'show_help': True,
         'expression_context': update_context,
     })
Ejemplo n.º 5
0
def pageview(request, page_code, page_type_code=None, overview=False):
    if page_type_code is None:
        page_type = return_default_page_type()
    else:
        page_type = get_object_or_404(PageType, code=page_type_code)

        if page_type.default:
            # for default type, don't allow longer URL with page_type_code
            # so that don't have two URLs pointing to same page
            from django.http import Http404
            raise Http404('No Page matches the given query.')

    thepage = get_object_or_404(Page, code=page_code, page_type=page_type)
    
    # get related pages
    max_keyword_matches=5
    max_total_related=10
    related_pages = get_all_related_pages(thepage,max_keyword_matches,max_total_related)
    if related_pages.get('generic') or related_pages.get('lighter') \
            or related_pages.get('depth'):
        manual_links=True
    else:
        manual_links=False
    
    
    # turn off google analytics for localhost/staging or hidden
    noanalytics=False
    if settings.SITE_ID <= 2 or thepage.hidden:
        noanalytics=True
        
    if request.method == 'GET':
        if "logout" in request.GET:
            auth.logout(request)

    
    notation_system=None
    notation_config=None
    notation_system_form=None

    if(thepage.notation_systems.all()):
        class NotationSystemForm(forms.Form):
            notation_system = forms.ModelChoiceField(queryset=thepage.notation_systems.all(), initial=1)


        # if submitted the notation_system form
        if request.method == 'POST':
            notation_system_form = NotationSystemForm(request.POST)
            if notation_system_form.is_valid():
                notation_system = notation_system_form.cleaned_data['notation_system']
                request.session['notation_config'] = notation_system.configfile
                notation_config = notation_system.configfile
            # if invalid form, get notation config from session
            else:
                notation_config = request.session.get('notation_config', '')

        # if did not submit the notation_system form
        else:
            notation_config = request.session.get('notation_config', None)
            if(notation_config):
                try:
                    notation_system = thepage.notation_systems.get(configfile=notation_config)
                except:
                    notation_system = None
                    notation_config = None

            # if got the notation sytem from the session,
            # show that system selected in the form
            if(notation_system):
                notation_system_form = NotationSystemForm({'notation_system': notation_system.pk})
            # otherwise show an unbound form with default as initial value
            else:
                notation_system_form = NotationSystemForm()

        # if have midefault system, delete it from notation_config
        # since template already has midefault hard coded in it
        if(notation_config=='midefault'):
            notation_config=None

    from micourses.utils import find_last_course
    last_course = find_last_course(user=request.user, request=request)

    # find thread content from active threads.
    # put thread content from any 
    # enrolled course or last course viewed at top
    thread_content_list = list(thepage.thread_content_set\
                               .filter(course__active=True))
    if last_course:
        for tc in thepage.thread_content_set.filter(course=last_course)\
                            .reverse():
            try:
                thread_content_list.remove(tc)
            except ValueError:
                pass
            thread_content_list.insert(0,tc)
        
    # render page text with extra template tags
    context = Context({})
    from midocs.functions import return_new_auxiliary_data
    context['_auxiliary_data_'] = return_new_auxiliary_data()
    context['_auxiliary_data_']['page_type'] = page_type.code
    context['thepage'] = thepage
    context['notation_system']=notation_system
    context['STATIC_URL'] = settings.STATIC_URL
    context['MEDIA_URL'] = settings.MEDIA_URL
    context['last_course'] = last_course
    context['thread_content_list'] = thread_content_list

    if thepage.text:
        try:
            rendered_text = Template("{% load mi_tags question_tags %}"+thepage.text).render(context)
        except Exception as e:
            rendered_text = "Template error in text (TMPLERR): %s" % e
    else:
        rendered_text = ""

    if thepage.header:
        try:
            rendered_header = Template("{% load mi_tags question_tags %}"+thepage.header).render(context)
        except Exception as e:
            rendered_header = ""
            rendered_text = "<p>Template error in text (TMPLERR): %s</p> %s" \
                            % (e, rendered_text)
    else:
        rendered_header = ""

    if thepage.javascript:
        try:
            rendered_javascript = Template("{% load mi_tags question_tags %}"+thepage.javascript).render(context)
        except Exception as e:
            rendered_javascript = ""
            rendered_text = "<p>Template error in text (TMPLERR): %s</p> %s" \
                            % (e, rendered_text)
    else:
        rendered_javascript = ""

    templates = ["midocs/%s_detail.html" % page_type.code, "midocs/page_detail.html"]

    if request.GET.get("bare"):
        templates = ["midocs/%s_bare.html" % page_type.code, "midocs/page_bare.html"] + templates




    context.update({'related_pages': related_pages,
                    'manual_links': manual_links,
                    'notation_config': notation_config,
                    'notation_system_form': notation_system_form,
                    'noanalytics': noanalytics,
                    'rendered_text': rendered_text,
                    'rendered_header': rendered_header,
                    'rendered_javascript': rendered_javascript,
                });

    return render(request, templates, context=context.flatten() )
Ejemplo n.º 6
0
def appletview(request, applet_code):

    theapplet = get_object_or_404(Applet, code=applet_code)
    
    in_pages=theapplet.in_pages.all()

    # turn off google analytics for localhost/staging or hidden
    noanalytics=False
    if settings.SITE_ID <= 2 or theapplet.hidden:
        noanalytics=True

    if request.method == 'GET':
        if "logout" in request.GET:
            auth.logout(request)

    notation_system=None
    notation_config=None
    notation_system_form=None

    if(theapplet.notation_systems.all()):
        class NotationSystemForm(forms.Form):
            notation_system = forms.ModelChoiceField(queryset=theapplet.notation_systems.all(), initial=1)


        # if submitted the notation_system form
        if request.method == 'POST':
            notation_system_form = NotationSystemForm(request.POST)
            if notation_system_form.is_valid():
                notation_system = notation_system_form.cleaned_data['notation_system']
                request.session['notation_config'] = notation_system.configfile
                notation_config = notation_system.configfile
            # if invalid form, get notation config from session
            else:
                notation_config = request.session.get('notation_config', '')

        # if did not submit the notation_system form
        else:
            notation_config = request.session.get('notation_config', None)
            if(notation_config):
                try:
                    notation_system = theapplet.notation_systems.get(configfile=notation_config)
                except:
                    notation_system = None
                    notation_config = None

            # if got the notation sytem from the session,
            # show that system selected in the form
            if(notation_system):
                notation_system_form = NotationSystemForm({'notation_system': notation_system.pk})
            # otherwise show an unbound form with default as initial value
            else:
                notation_system_form = NotationSystemForm()

        # if have midefault system, delete it from notation_config
        # since template already has midefault hard coded in it
        if(notation_config=='midefault'):
            notation_config=None
    

    applet_filename = re.sub(settings.APPLET_UPLOAD_TO,"", theapplet.applet_file.name)  # get rid of upload path

    applet_filename2=None
    if theapplet.applet_file2:
        applet_filename2 = re.sub(settings.APPLET_UPLOAD_TO,"", theapplet.applet_file2.name)  # get rid of upload path


    from midocs.functions import return_new_auxiliary_data
    auxiliary_data = return_new_auxiliary_data()

    return render(request, "midocs/applet_detail.html", 
                  {'applet': theapplet, 'in_pages': in_pages,
                   'applet_filename': applet_filename,
                   'applet_filename2': applet_filename2,
                   'notation_config': notation_config,
                   'notation_system_form': notation_system_form,
                   'noanalytics': noanalytics,
                   '_auxiliary_data_': auxiliary_data,
               })
Ejemplo n.º 7
0
    def post(self, request, *args, **kwargs):
        # Look up the question to grade
        question = self.get_object()
        

        pairs = [s2 for s1 in request.body.split(b'&') for s2 in s1.split(b';')]
        cgd = None
        for name_value in pairs:
            if not name_value:
                continue
            nv = name_value.split(b'=', 1)
            if len(nv) != 2:
                continue
            
            if nv[0]==b'cgd':
                cgd = nv[1]
                break

        import pickle, base64, binascii
        try:
            computer_grade_data = pickle.loads(
                base64.b64decode(cgd))
        except (TypeError, IndexError, EOFError, binascii.Error) as exc:
            logger.error("cgd malformed: %s" % exc)
            return JsonResponse({})

        course_code = computer_grade_data.get('course_code')
        assessment_code = computer_grade_data.get('assessment_code')
        
        assessment = None
        course=None

        if assessment_code and course_code:
            try:
                from micourses.models import Assessment
                assessment = Assessment.objects.get(course__code=course_code,
                                                    code=assessment_code)
                course=assessment.course
            except ObjectDoesNotExist:
                assessment_code = None

        # if user cannot view question solution,
        # or if user cannot view assessment solution (in case question is
        # part of an assessment)
        # then return empty json object
        if not question.user_can_view(request.user, solution=True, 
                                      course=course):
            return JsonResponse({})
        if assessment:
            if not assessment.user_can_view(request.user, solution=True,
                                            include_questions=False):
                return JsonResponse({})


        question_identifier = computer_grade_data['identifier']

        # set up context from question expressions
        seed = computer_grade_data['seed']

        from midocs.functions import return_new_auxiliary_data
        auxiliary_data =  return_new_auxiliary_data()
        auxiliary_data['applet']['suffix'] = "%s_sol" % question_identifier

        question_attempt=None
        question_attempt_id = computer_grade_data.get("question_attempt_id")
        if question_attempt_id is not None:
            try:
                from micourses.models import QuestionAttempt
                question_attempt = QuestionAttempt.objects.get(
                    id=question_attempt_id)
            except QuestionAttempt.DoesNotExist:
                pass

        import random
        rng=random.Random()

        question_dict={
            'question': question,
            'seed': seed,
            'question_attempt': question_attempt,
         }

        from mitesting.render_questions import render_question
        question_data= render_question(
            question_dict=question_dict,
            rng=rng, user=request.user,
            question_identifier="%s_sol" % question_identifier, 
            auxiliary_data = auxiliary_data,
            solution=True,
            show_help = False)

        from django.template.loader import get_template
        question_solution_template = get_template(
            "mitesting/question_solution_body.html")
        rendered_solution = question_solution_template.render(
                {'question_data': question_data})

        rendered_solution = mark_safe("<h4>Solution</h4>" + rendered_solution)
        results = {'rendered_solution': rendered_solution,
                   'identifier': question_identifier,
                   'applet_javascript': auxiliary_data['applet']['javascript'],
                   }


        
        # if not from a question attempt, then just return solution
        # and don't record fact
        if not question_attempt:
            return JsonResponse(results)

        
        ce = course.courseenrollment_set.get(student=request.user.courseuser)

        own_attempt = True
        if ce != question_attempt.content_attempt_question_set\
                                 .content_attempt.record.enrollment:
            own_attempt = False
        
        # if not an instructor, then show solution only if question attempt
        # is own attempt
        from micourses.models import INSTRUCTOR_ROLE, DESIGNER_ROLE
        if not (ce.role == INSTRUCTOR_ROLE or ce.role == DESIGNER_ROLE):
            if not own_attempt:
                return JsonResponse({})

        if own_attempt and not question_attempt.solution_viewed:
            # record fact that viewed solution for this question_attempt
            question_attempt.solution_viewed = timezone.now()
            for trans_i in range(5):
                try:
                    with transaction.atomic(), reversion.create_revision():
                        question_attempt.save()
                except OperationalError:
                    if trans_i==4:
                        raise
                else:
                    break

        # return solution
        return JsonResponse(results)
Ejemplo n.º 8
0
    def get_context_data(self, **kwargs):
        context = super(AssessmentView, self).get_context_data(**kwargs)


        from midocs.functions import return_new_auxiliary_data
        auxiliary_data =  return_new_auxiliary_data()
        context['_auxiliary_data_'] = auxiliary_data

        import random
        rng=random.Random()

        # show post user response errors only if instructor permissions
        if user_has_given_assessment_permission_level(
                self.request.user, 2):
            show_post_user_errors=True
        else:
            show_post_user_errors=False

        from micourses.render_assessments import render_question_list
        rendered_list=render_question_list(
            self.assessment, self.question_list, rng=rng, 
            assessment_seed=self.assessment_seed, 
            user=self.request.user, 
            solution=self.solution,
            auxiliary_data = auxiliary_data,
            show_post_user_errors=show_post_user_errors)

        # if question_only is set, then view only that question
        if self.kwargs.get('question_only'):
            question_only = int(self.kwargs['question_only'])
            rendered_list=rendered_list[question_only-1:question_only]
            context['question_only'] = question_only
        context['rendered_list'] = rendered_list

        context['seed'] = self.assessment_seed

        # determine if there were any errors
        success=True
        question_errors=[]
        for (ind,q) in enumerate(rendered_list):
            if not q["question_data"]["success"]:
                success=False
                question_errors.append(str(ind+1))
        if not success:
            context['error_message'] = \
                "Errors occurred in the following questions: %s" %\
                ", ".join(question_errors)

        context['success'] = success
        
        context['generate_course_attempt_link'] = False
        context['show_solution_link'] = False

        course = self.assessment.course
        context['course'] = course
        
        if user_can_administer_assessment(self.request.user, course=course):
            if self.thread_content:
                context['generate_course_attempt_link'] = True
            if not self.solution:
                context['show_solution_link'] = True

        if self.thread_content:
            context['assessment_name'] = self.thread_content.get_title()
        else:
            context['assessment_name'] = self.assessment.name
        if self.solution:
            context['assessment_name'] += " solution"
        context['assessment_short_name'] = self.assessment.return_short_name()
        if self.solution:
            context['assessment_short_name'] += " sol."

        if self.version:
            context['version'] =  self.version
            context['assessment_name_with_version'] = "%s, version %s" % \
                        (context['assessment_name'], context['version'])
            context['assessment_short_name_with_version'] = "%s, version %s" % \
                        (context['assessment_short_name'], context['version'])
        else:
            context['version'] = ''
            context['assessment_name_with_version'] = context['assessment_name']
            context['assessment_short_name_with_version'] \
                = context['assessment_short_name']

        if self.course_enrollment and self.thread_content:
            if self.course_enrollment.role == STUDENT_ROLE and self.current_attempt:
                due = self.thread_content.get_adjusted_due(
                    self.current_attempt.record)

                if course.adjust_due_attendance and due:
                    due_date_url = reverse(
                        'micourses:adjusted_due_calculation',
                        kwargs={'course_code': course.code,
                                'content_id': self.thread_content.id }
                    )
                    from micourses.utils import format_datetime
                    current_tz = timezone.get_current_timezone()
                    due_string = format_datetime(current_tz.normalize(
                        due.astimezone(current_tz)))
                    due = mark_safe('<a href="%s">%s</a>' % \
                                               (due_date_url, due_string))
                context['due'] = due
            else:
                context['due'] = self.thread_content.get_adjusted_due()

        context['thread_content'] = self.thread_content
        context['number_in_thread'] = self.number_in_thread
        context['current_attempt'] = self.current_attempt

        context['users attempt'] = False
        context['multiple_attempts'] = False
        context['attempt_url']=None
        context['record_url']=None


        # set date from current_attempt, else as now
        if self.current_attempt:
            context['assessment_date'] = self.current_attempt.attempt_began
        else:
            context['assessment_date'] = timezone.now()


        # Check if have current attempt that belongs to user
        # (so can show score)
        # Create links to record and attempts (if valid)

        if self.current_attempt and \
           self.current_attempt.record.enrollment == self.course_enrollment:

            context['users_attempt'] = True

            valid_attempt_list = list(
                self.current_attempt.record.attempts.filter(valid=True))
            context['multiple_attempts'] = len(valid_attempt_list)>1

            context['record_url'] = reverse(
                'micourses:content_record',
                kwargs={'course_code': course.code,
                        'content_id': self.thread_content.id})

            if self.current_attempt.valid:
                attempt_number = valid_attempt_list.index(self.current_attempt)\
                                 +1
                context['attempt_url'] = reverse(
                    'micourses:content_attempt', 
                    kwargs={'course_code': course.code,
                            'content_id': self.thread_content.id,
                            'attempt_number': attempt_number})

                # add question attempt urls to rendered_list question_data
                for (ind,q) in enumerate(rendered_list):
                    q["question_data"]["attempt_url"] = reverse(
                        'micourses:question_attempts', 
                        kwargs={'course_code': course.code, 
                                'content_id': self.thread_content.id, 
                                'attempt_number': attempt_number, 
                                'question_number': ind+1} )



        from mitesting.utils import round_and_int
        if self.thread_content:
            context['thread_content_points'] = round_and_int(
                self.thread_content.points)
        if self.current_attempt is None or self.current_attempt.score is None:
            context['attempt_score']=0
        else:
            context['attempt_score']=round_and_int(
                self.current_attempt.score,1)
        
        if self.current_attempt is None or \
           self.current_attempt.record.score is None:
            context['content_score']=0
        else:
            context['content_score']=round_and_int(
                self.current_attempt.record.score,1)


        # get list of the question numbers in assessment
        # if instructor or designer in course
        # if also staff, include links to admin pages
        if user_can_administer_assessment(self.request.user, course=course):
            question_numbers=[]
            if self.request.user.is_staff:
                context['assessment_admin_link'] = mark_safe(
                    "<p><a href='%s'>%s</a></p>" % (
                        reverse('admin:micourses_assessment_change',
                                args=(self.assessment.id,)),
                        'Admin link'))
            for q in rendered_list:
                # if staff, add link to admin page for quesiton
                if self.request.user.is_staff:
                    question_numbers.append(
                        "<a href='%s'>%s</a>" % (
                            reverse('admin:mitesting_question_change',
                                    args=(q['question'].id,)),
                            q['question'].id)
                    )
                else:
                    question_numbers.append(str(q['question'].id))
            question_numbers = ", ".join(question_numbers)
            question_numbers = mark_safe(question_numbers)
        else:
            question_numbers=None
        context['question_numbers']=question_numbers

        # turn off Google analytics for localhost/development site
        context['noanalytics']=(settings.SITE_ID <= 2)

        from mitesting.utils import get_new_seed
        context['new_seed']=get_new_seed(rng)

        return context