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
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, })
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
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, })
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() )
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, })
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)
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