summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
authorprathamesh2017-12-27 17:32:21 +0530
committerprathamesh2017-12-27 17:53:50 +0530
commit51a93b42b1d7b3a94e227796aa8d4f6e97de9929 (patch)
treedb35061da2b9891dd597337be78946eb67c5df3c /yaksh
parentb44db042059e69df4c4a948d6dff73604c7abf83 (diff)
downloadonline_test-51a93b42b1d7b3a94e227796aa8d4f6e97de9929.tar.gz
online_test-51a93b42b1d7b3a94e227796aa8d4f6e97de9929.tar.bz2
online_test-51a93b42b1d7b3a94e227796aa8d4f6e97de9929.zip
Exercise feature in video lessons
Exercise is same as quiz except for following differences: - no time limit - no marks weightage - no instruction page - skip denied for a particular time An attribute 'is_exercise' in Quiz determines whether the quiz is exercise or not. Questions contains 'min_time' attribute. For an exercise a question cannot be skipped for an allotted minimum time, after which either django or JavaScript makes Next button available. Implementation is as such due to complexity of our existing views and templates. Also, after min_time, same question with Next button is available to move on, assuming that solution is present in the video.
Diffstat (limited to 'yaksh')
-rw-r--r--yaksh/forms.py8
-rw-r--r--yaksh/models.py20
-rw-r--r--yaksh/static/yaksh/js/requesthandler.js7
-rw-r--r--yaksh/templates/exam.html4
-rw-r--r--yaksh/templates/yaksh/add_exercise.html41
-rw-r--r--yaksh/templates/yaksh/add_question.html1
-rw-r--r--yaksh/templates/yaksh/courses.html7
-rw-r--r--yaksh/templates/yaksh/question.html37
-rw-r--r--yaksh/test_views.py100
-rw-r--r--yaksh/urls.py3
-rw-r--r--yaksh/views.py130
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>&nbsp;&nbsp;
{% 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>&nbsp;&nbsp;
{% 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()