diff options
-rw-r--r-- | yaksh/forms.py | 8 | ||||
-rw-r--r-- | yaksh/models.py | 20 | ||||
-rw-r--r-- | yaksh/static/yaksh/js/requesthandler.js | 7 | ||||
-rw-r--r-- | yaksh/templates/exam.html | 4 | ||||
-rw-r--r-- | yaksh/templates/yaksh/add_exercise.html | 41 | ||||
-rw-r--r-- | yaksh/templates/yaksh/add_question.html | 1 | ||||
-rw-r--r-- | yaksh/templates/yaksh/courses.html | 7 | ||||
-rw-r--r-- | yaksh/templates/yaksh/question.html | 37 | ||||
-rw-r--r-- | yaksh/test_views.py | 100 | ||||
-rw-r--r-- | yaksh/urls.py | 3 | ||||
-rw-r--r-- | yaksh/views.py | 130 |
11 files changed, 318 insertions, 40 deletions
diff --git a/yaksh/forms.py b/yaksh/forms.py index 52e6a12..84db33e 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -173,6 +173,12 @@ class UserLoginForm(forms.Form): return user +class ExerciseForm(forms.ModelForm): + class Meta: + model = Quiz + fields = ['description'] + + class QuizForm(forms.ModelForm): """Creates a form to add or edit a Quiz. It has the related fields and functions required.""" @@ -209,7 +215,7 @@ class QuizForm(forms.ModelForm): class Meta: model = Quiz - exclude = ["is_trial", "creator"] + exclude = ["is_trial", "creator", "is_exercise"] class QuestionForm(forms.ModelForm): diff --git a/yaksh/models.py b/yaksh/models.py index c65e9ef..839043f 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -308,6 +308,8 @@ class Quiz(models.Model): weightage = models.FloatField(default=1.0) + is_exercise = models.BooleanField(default=False) + creator = models.ForeignKey(User, null=True) objects = QuizManager() @@ -747,6 +749,8 @@ class Question(models.Model): # Check assignment upload based question grade_assignment_upload = models.BooleanField(default=False) + min_time = models.IntegerField("time in minutes", default=0) + def consolidate_answer_data(self, user_answer, user=None): question_data = {} metadata = {} @@ -1517,15 +1521,25 @@ class AnswerPaper(models.Model): def time_left(self): """Return the time remaining for the user in seconds.""" + secs = self._get_total_seconds() + total = self.question_paper.quiz.duration*60.0 + remain = max(total - secs, 0) + return int(remain) + + def time_left_on_question(self, question): + secs = self._get_total_seconds() + total = question.min_time*60.0 + remain = max(total - secs, 0) + return int(remain) + + def _get_total_seconds(self): dt = timezone.now() - self.start_time try: secs = dt.total_seconds() except AttributeError: # total_seconds is new in Python 2.7. :( secs = dt.seconds + dt.days*24*3600 - total = self.question_paper.quiz.duration*60.0 - remain = max(total - secs, 0) - return int(remain) + return secs def _update_marks_obtained(self): """Updates the total marks earned by student for this paper.""" diff --git a/yaksh/static/yaksh/js/requesthandler.js b/yaksh/static/yaksh/js/requesthandler.js index 0663a55..f50570b 100644 --- a/yaksh/static/yaksh/js/requesthandler.js +++ b/yaksh/static/yaksh/js/requesthandler.js @@ -36,6 +36,10 @@ function unlock_screen() { document.getElementById("ontop").style.display = "none"; } +function show_skip() { + document.getElementById("skip_ex").style.visibility = "visible"; +} + function get_result(uid){ var url = "/exam/get_result/" + uid + "/" + course_id + "/" + module_id + "/"; ajax_check_code(url, "GET", "html", null, uid) @@ -104,6 +108,9 @@ function ajax_check_code(url, method_type, data_type, data, uid) { var global_editor = {}; $(document).ready(function(){ + if(is_exercise == "True" && can_skip == "False"){ + setTimeout(function() {show_skip();}, delay_time*1000); + } // Codemirror object, language modes and initial content // Get the textarea node var textarea_node = document.querySelector('#answer'); diff --git a/yaksh/templates/exam.html b/yaksh/templates/exam.html index d0812a4..4fd83dd 100644 --- a/yaksh/templates/exam.html +++ b/yaksh/templates/exam.html @@ -20,9 +20,9 @@ <ul class="nav navbar-nav navbar"> <li style="padding: 10px"><button class="btn btn-danger btn-sm" type="submit" name="quit"> {% if paper.questions_unanswered.all %} - Quit Exam + Quit {{ quiz_type }} {% else %} - Finish Exam + Finish {{ quiz_type }} {% endif %} <span class="glyphicon glyphicon-off"></span></button></li> </ul> diff --git a/yaksh/templates/yaksh/add_exercise.html b/yaksh/templates/yaksh/add_exercise.html new file mode 100644 index 0000000..af3e7b4 --- /dev/null +++ b/yaksh/templates/yaksh/add_exercise.html @@ -0,0 +1,41 @@ +{% extends "manage.html" %} + + +{% block subtitle %}Add Exercise{% endblock %} + +{% block css %} +<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/question_quiz.css" type="text/css" /> +<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/jquery.datetimepicker.css" type="text/css" /> +{% endblock %} +{% block script %} +<script src="{{ URL_ROOT }}/static/yaksh/js/jquery-1.9.1.min.js"></script> +<script src="{{ URL_ROOT }}/static/yaksh/js/add_quiz.js"></script> +<script src="{{ URL_ROOT }}/static/yaksh/js/jquery.datetimepicker.full.min.js"></script> +{% endblock %} +{% block onload %} onload="javascript:test();" {% endblock %} +{% block content %} + +<form name=frm id=frm action="" method="post" > + {% csrf_token %} + <center> + <table class="span1 table"> + {{ form.as_table }} + </table> + <script type="text/javascript"> + $("#id_start_date_time").datetimepicker({format: 'Y-m-d H:i:s'}); + $("#id_end_date_time").datetimepicker({format: 'Y-m-d H:i:s'}); + </script> + <br/><br/> + </center> + + <center><button class="btn" type="submit" id="submit" name="questionpaper"> Save + </button> + + <button class="btn" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/courses/");'>Cancel</button> </center> +</form> + <style type="text/css"> + #rendered_text{ + width: 550px; + } + </style> +{% endblock %} diff --git a/yaksh/templates/yaksh/add_question.html b/yaksh/templates/yaksh/add_question.html index 6ead019..c294d9a 100644 --- a/yaksh/templates/yaksh/add_question.html +++ b/yaksh/templates/yaksh/add_question.html @@ -25,6 +25,7 @@ <tr><td>Description: <td>{{ qform.description}} {{qform.description.errors}} <tr><td>Tags: <td>{{ qform.tags }} <tr><td>Snippet: <td>{{ qform.snippet }} + <tr><td>Minimum Time(in minutes):<td> {{ qform.min_time }} <tr><td>Partial Grading: <td>{{ qform.partial_grading }} <tr><td>Grade Assignment Upload:<td> {{ qform.grade_assignment_upload }} <tr><td> File: <td> {{ fileform.file_field }}{{ fileform.file_field.errors }} diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html index 5daf944..a06ee7e 100644 --- a/yaksh/templates/yaksh/courses.html +++ b/yaksh/templates/yaksh/courses.html @@ -290,7 +290,8 @@ <div id="all_quizzes" > <div class="col-md-offset-2 main"> {% if type == "quiz" %} - <a href="{{URL_ROOT}}/exam/manage/addquiz/" class="btn btn-primary">Add new Quiz</a> + <a href="{{URL_ROOT}}/exam/manage/addquiz/" class="btn btn-primary">Add New Quiz</a> + <a href="{{URL_ROOT}}/exam/manage/add_exercise/" class="btn btn-primary">Add New Exercise</a> {% if not quizzes %} <center><h4> No new Quiz Added</h4></center> <br><br> @@ -308,7 +309,11 @@ <td>{{forloop.counter}}</td> <td width="30%"> <ul class="list-group"> + {% if quiz.is_exercise %} + <a href="{{URL_ROOT}}/exam/manage/add_exercise/{{quiz.id}}/">{{ quiz.description }}</a> + {% else %} <a href="{{URL_ROOT}}/exam/manage/addquiz/{{quiz.id}}/">{{ quiz.description }}</a> + {% endif %} {% if quiz.active %} <span class="label label-success">Active</span> {% else %} diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html index 6adda5b..978d226 100644 --- a/yaksh/templates/yaksh/question.html +++ b/yaksh/templates/yaksh/question.html @@ -23,7 +23,18 @@ <script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script> <script> +init_val = '{{ last_attempt|escape_quotes|safe }}'; +lang = "{{ question.language }}" +course_id = "{{course.id}}" +module_id = "{{module.id}}" +is_exercise = "{{ quiz.is_exercise }}" +can_skip = "{{ can_skip }}" +delay_time = new Number("{{ delay_time }}") + var time_left = {{ paper.time_left }} +{% if quiz.is_exercise %} + time_left = {{ delay_time }} +{% endif %} function getTimeRemaining(endtime){ var t = Date.parse(endtime) - Date.parse(new Date()); @@ -52,13 +63,15 @@ function updateClock(){ var mm = ('0' + t.minutes).slice(-2); var ss = ('0' + t.seconds).slice(-2); - if(t.total<0){ - + if(t.total<0 && is_exercise=="False"){ document.forms["code"].submit(); clearInterval(timeinterval); return null; } - if (t.total<=300000){ + if(t.total<=0 && is_exercise=="True"){ + clearInterval(timeinterval); + } + if (t.total<=300000 && t.total > 0){ clock.innerHTML = "<blink><center><span style='color:red'><strong>" + hh + ":" + mm + ":" + ss + "</strong></center></span></blink>"; } if (t.total>=300000) { @@ -68,6 +81,7 @@ function updateClock(){ var clock = document.getElementById("time_left"); updateClock(); var timeinterval = setInterval(updateClock,1000); + } function validate(){ @@ -85,13 +99,7 @@ function call_skip(url) form.action = url form.submit(); } -init_val = '{{ last_attempt|escape_quotes|safe }}'; -lang = "{{ question.language }}" -course_id = "{{course.id}}" -module_id = "{{module.id}}" - </script> - {% endblock script %} {% block onload %} onload="updateTime();" {% endblock %} @@ -253,16 +261,23 @@ module_id = "{{module.id}}" <br><button class="btn btn-primary" type="submit" name="check" id="check" onClick="return validate();">Upload</button> {% else %} - {% if question in paper.get_questions_unanswered %} + {% if question in paper.get_questions_unanswered or quiz.is_exercise %} <button class="btn btn-primary" type="submit" name="check" id="check" >Check Answer <span class="glyphicon glyphicon-cog"></span></button> {% endif %} {% endif %} + {% if quiz.is_exercise %} + {% if can_skip %} + <button id="skip_ex" class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip"> Next <span class="glyphicon glyphicon-arrow-right"></span></button> + {% else %} + <button id="skip_ex" class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip" style="visibility:hidden"> Next <span class="glyphicon glyphicon-arrow-right"></span></button> + {% endif %} + {% endif %} {% if paper.question_paper.quiz.allow_skip and not paper.get_questions_unanswered|length_is:"1" %} {% if question in paper.get_questions_unanswered %} <button class="btn btn-primary" onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')" name="skip" id="skip">Attempt Later <span class="glyphicon glyphicon-arrow-right"></span></button> {% endif %} - {% endif %} + {% endif %} </div> </form> </div> diff --git a/yaksh/test_views.py b/yaksh/test_views.py index d65fe8e..38564a1 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -1042,11 +1042,19 @@ class TestAddQuiz(TestCase): creator=self.user ) + self.exercise = Quiz.objects.create( + start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), + end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzone), + attempts_allowed=-1, time_between_attempts=0, + is_exercise=True, description='demo exercise', creator=self.user + ) + def tearDown(self): self.client.logout() self.user.delete() self.student.delete() self.quiz.delete() + self.exercise.delete() self.course.delete() def test_add_quiz_denies_anonymous(self): @@ -1171,6 +1179,98 @@ class TestAddQuiz(TestCase): self.assertEqual(response.status_code, 302) self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') + def test_add_exercise_denies_anonymous(self): + """ + If not logged in redirect to login page + """ + response = self.client.get(reverse('yaksh:add_exercise'), + follow=True + ) + redirect_destination = '/exam/login/?next=/exam/manage/add_exercise/' + self.assertRedirects(response, redirect_destination) + + def test_add_exercise_denies_non_moderator(self): + """ + If not moderator in redirect to login page + """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + course_id = self.course.id + response = self.client.get(reverse('yaksh:add_exercise'), + follow=True + ) + self.assertEqual(response.status_code, 404) + + def test_add_exercise_get(self): + """ + GET request to add exercise should display add exercise form + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:add_exercise') + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_exercise.html') + self.assertIsNotNone(response.context['form']) + + def test_add_exercise_post_existing_exercise(self): + """ + POST request to edit exercise + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + tzone = pytz.timezone('UTC') + response = self.client.post(reverse('yaksh:add_exercise', + kwargs={'quiz_id': self.exercise.id}), + data={ + 'description': 'updated demo exercise', + } + ) + + updated_exercise = Quiz.objects.get(id=self.exercise.id) + self.assertEqual(updated_exercise.active, True) + self.assertEqual(updated_exercise.duration, 1000) + self.assertEqual(updated_exercise.attempts_allowed, -1) + self.assertEqual(updated_exercise.time_between_attempts, 0) + self.assertEqual(updated_exercise.description, 'updated demo exercise') + self.assertEqual(updated_exercise.pass_criteria, 0) + self.assertTrue(updated_exercise.is_exercise) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') + + def test_add_exercise_post_new_exercise(self): + """ + POST request to add new exercise + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + tzone = pytz.timezone('UTC') + response = self.client.post(reverse('yaksh:add_exercise'), + data={ + 'description': "Demo Exercise", + } + ) + quiz_list = Quiz.objects.all().order_by('-id') + new_exercise = quiz_list[0] + self.assertEqual(new_exercise.active, True) + self.assertEqual(new_exercise.duration, 1000) + self.assertEqual(new_exercise.attempts_allowed, -1) + self.assertEqual(new_exercise.time_between_attempts, 0) + self.assertEqual(new_exercise.description, 'Demo Exercise') + self.assertEqual(new_exercise.pass_criteria, 0) + self.assertTrue(new_exercise.is_exercise) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') + def test_show_all_quizzes(self): self.client.login( username=self.user.username, diff --git a/yaksh/urls.py b/yaksh/urls.py index 716a7d0..f7df456 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -49,6 +49,9 @@ urlpatterns = [ url(r'^manage/addquestion/(?P<question_id>\d+)/$', views.add_question, name="add_question"), url(r'^manage/addquiz/$', views.add_quiz, name='add_quiz'), + url(r'^manage/add_exercise/$', views.add_exercise, name='add_exercise'), + url(r'^manage/add_exercise/(?P<quiz_id>\d+)/$', views.add_exercise, + name='add_exercise'), url(r'^manage/addquiz/(?P<quiz_id>\d+)/$', views.add_quiz, name='edit_quiz'), url(r'^manage/addquiz/(?P<quiz_id>\d+)/(?P<course_id>\d+)$', diff --git a/yaksh/views.py b/yaksh/views.py index 483b87c..302ef9e 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -46,7 +46,7 @@ from yaksh.forms import ( UserRegisterForm, UserLoginForm, QuizForm, QuestionForm, RandomQuestionForm, QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm, get_object_form, FileForm, QuestionPaperForm, LessonForm, - LessonFileForm, LearningModuleForm + LessonFileForm, LearningModuleForm, ExerciseForm ) from .settings import URL_ROOT from .file_utils import extract_files, is_csv @@ -327,6 +327,56 @@ def add_quiz(request, quiz_id=None, course_id=None): @login_required +@email_verified +def add_exercise(request, quiz_id=None, course_id=None): + user = request.user + ci = RequestContext(request) + if not is_moderator(user): + raise Http404('You are not allowed to view this course !') + if quiz_id: + quiz = get_object_or_404(Quiz, pk=quiz_id) + if quiz.creator != user and not course_id: + raise Http404('This quiz does not belong to you') + else: + quiz = None + if course_id: + course = get_object_or_404(Course, pk=course_id) + if not course.is_creator(user) and not course.is_teacher(user): + raise Http404('This quiz does not belong to you') + + context = {} + if request.method == "POST": + form = ExerciseForm(request.POST, instance=quiz) + if form.is_valid(): + if quiz is None: + form.instance.creator = user + quiz = form.save(commit=False) + quiz.is_exercise = True + quiz.time_between_attempts = 0 + quiz.weightage = 0 + quiz.allow_skip = False + quiz.attempts_allowed = -1 + quiz.duration = 1000 + quiz.pass_criteria = 0 + quiz.save() + + if not course_id: + return my_redirect("/exam/manage/courses/all_quizzes/") + else: + return my_redirect("/exam/manage/courses/") + + else: + quiz = Quiz.objects.get(id=quiz_id) if quiz_id else None + form = ExerciseForm(instance=quiz) + context["quiz_id"] = quiz_id + context["course_id"] = course_id + context["form"] = form + return my_render_to_response( + 'yaksh/add_exercise.html', context, context_instance=ci + ) + + +@login_required @has_profile @email_verified def prof_manage(request, msg=None): @@ -460,7 +510,8 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None, if last_attempt and last_attempt.is_attempt_inprogress(): return show_question( request, last_attempt.current_question(), last_attempt, - course_id=course_id, module_id=module_id + course_id=course_id, module_id=module_id, + previous_question=last_attempt.current_question() ) # allowed to start if not quest_paper.can_attempt_now(user, course_id): @@ -474,7 +525,7 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None, attempt_number = 1 else: attempt_number = last_attempt.attempt_number + 1 - if attempt_num is None: + if attempt_num is None and not quest_paper.quiz.is_exercise: context = { 'user': user, 'questionpaper': quest_paper, @@ -496,7 +547,7 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None, if new_paper.status == 'inprogress': return show_question(request, new_paper.current_question(), new_paper, course_id=course_id, - module_id=module_id + module_id=module_id, previous_question=None ) else: msg = 'You have already finished the quiz!' @@ -505,27 +556,42 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None, @login_required @email_verified def show_question(request, question, paper, error_message=None, notification=None, - course_id=None, module_id=None): + course_id=None, module_id=None, previous_question=None): """Show a question if possible.""" user = request.user + quiz = paper.question_paper.quiz + quiz_type = 'Exam' + can_skip = False + if previous_question: + delay_time = paper.time_left_on_question(previous_question) + else: + delay_time = paper.time_left_on_question(question) + + if previous_question and quiz.is_exercise: + if delay_time <= 0: + can_skip = True + question = previous_question if not question: msg = 'Congratulations! You have successfully completed the quiz.' return complete( request, msg, paper.attempt_number, paper.question_paper.id, course_id=course_id, module_id=module_id ) - if not paper.question_paper.quiz.active: + if not quiz.active: reason = 'The quiz has been deactivated!' return complete( request, reason, paper.attempt_number, paper.question_paper.id, module_id=module_id ) - if paper.time_left() <= 0: - reason = 'Your time is up!' - return complete( - request, reason, paper.attempt_number, paper.question_paper.id, - course_id, module_id=module_id - ) + if not quiz.is_exercise: + if paper.time_left() <= 0: + reason = 'Your time is up!' + return complete( + request, reason, paper.attempt_number, paper.question_paper.id, + course_id, module_id=module_id + ) + else: + quiz_type = 'Exercise' if question in paper.questions_answered.all(): notification = ( 'You have already attempted this question successfully' @@ -539,13 +605,17 @@ def show_question(request, question, paper, error_message=None, notification=Non context = { 'question': question, 'paper': paper, + 'quiz': quiz, 'error_message': error_message, 'test_cases': test_cases, 'files': files, 'notification': notification, 'last_attempt': question.snippet.encode('unicode-escape'), 'course': course, - 'module': module + 'module': module, + 'can_skip': can_skip, + 'delay_time': delay_time, + 'quiz_type': quiz_type } answers = paper.get_previous_answers(question) if answers: @@ -568,6 +638,11 @@ def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None, ) question = get_object_or_404(Question, pk=q_id) + if paper.question_paper.quiz.is_exercise: + if paper.time_left_on_question(question) <= 0: + paper.start_time = timezone.now() + paper.save() + if request.method == 'POST' and question.type == 'code': if not paper.answers.filter(question=question, correct=True).exists(): user_code = request.POST.get('answer') @@ -612,7 +687,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None, msg = "Please enter an Integer Value" return show_question( request, current_question, paper, notification=msg, - course_id=course_id, module_id=module_id + course_id=course_id, module_id=module_id, + previous_question=current_question ) elif current_question.type == 'float': try: @@ -621,7 +697,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None, msg = "Please enter a Float Value" return show_question(request, current_question, paper, notification=msg, - course_id=course_id, module_id=module_id) + course_id=course_id, module_id=module_id, + previous_question=current_question) elif current_question.type == 'string': user_answer = str(request.POST.get('answer')) @@ -635,7 +712,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None, msg = "Please upload assignment file" return show_question( request, current_question, paper, notification=msg, - course_id=course_id, module_id=module_id + course_id=course_id, module_id=module_id, + previous_question=current_question ) for fname in assignment_filename: assignment_files = AssignmentUpload.objects.filter( @@ -663,14 +741,16 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None, paper.answers.add(new_answer) next_q = paper.add_completed_question(current_question.id) return show_question(request, next_q, paper, - course_id=course_id, module_id=module_id) + course_id=course_id, module_id=module_id, + previous_question=current_question) else: user_answer = request.POST.get('answer') if not user_answer: msg = "Please submit a valid answer." return show_question( request, current_question, paper, notification=msg, - course_id=course_id, module_id=module_id + course_id=course_id, module_id=module_id, + previous_question=current_question ) if current_question in paper.get_questions_answered()\ and current_question.type not in ['code', 'upload']: @@ -703,16 +783,19 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None, result) return show_question(request, next_question, paper, error_message, course_id=course_id, - module_id=module_id) + module_id=module_id, + previous_question=current_question) else: return JsonResponse(result) else: next_question, error_message, paper = _update_paper(request, uid, result) return show_question(request, next_question, paper, error_message, - course_id=course_id, module_id=module_id) + course_id=course_id, module_id=module_id, + previous_question=current_question) else: return show_question(request, current_question, paper, - course_id=course_id, module_id=module_id) + course_id=course_id, module_id=module_id, + previous_question=current_question) @csrf_exempt @@ -731,9 +814,12 @@ def get_result(request, uid, course_id, module_id): next_question, error_message, paper = _update_paper(request, uid, result ) + answer = Answer.objects.get(id=uid) + current_question = answer.question if result.get('success'): return show_question(request, next_question, paper, error_message, - course_id=course_id, module_id=module_id) + course_id=course_id, module_id=module_id, + previous_question=current_question) else: with open(template_path) as f: template_data = f.read() |