summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrabhu Ramachandran2017-03-08 15:59:18 +0530
committerGitHub2017-03-08 15:59:18 +0530
commit0a8000387b3edd463cc58b7fb85f76639f10b150 (patch)
tree3aba6618219a203a3bda5d4c85ef0ad1c229ab1d
parentaede1c3736077387d63eacd20c2c39d8875e605d (diff)
parentf57cfacf41f8a1d72a56ea8c875f906e7db2a15e (diff)
downloadonline_test-0a8000387b3edd463cc58b7fb85f76639f10b150.tar.gz
online_test-0a8000387b3edd463cc58b7fb85f76639f10b150.tar.bz2
online_test-0a8000387b3edd463cc58b7fb85f76639f10b150.zip
Merge pull request #229 from ankitjavalkar/reattempt-mcq
Allow to reattempt all types of questions
-rw-r--r--yaksh/live_server_tests/selenium_test.py4
-rw-r--r--yaksh/models.py17
-rw-r--r--yaksh/templates/exam.html4
-rw-r--r--yaksh/templates/yaksh/question.html37
-rw-r--r--yaksh/templates/yaksh/user_data.html4
-rw-r--r--yaksh/test_models.py10
-rw-r--r--yaksh/views.py27
7 files changed, 62 insertions, 41 deletions
diff --git a/yaksh/live_server_tests/selenium_test.py b/yaksh/live_server_tests/selenium_test.py
index d91f3ec..277f08e 100644
--- a/yaksh/live_server_tests/selenium_test.py
+++ b/yaksh/live_server_tests/selenium_test.py
@@ -29,8 +29,8 @@ class SeleniumTest():
except Exception as e:
self.driver.close()
msg = ("An Error occurred while running the Selenium load"
- " test on Yaksh!"
- "Error:\n ".format(e))
+ " test on Yaksh!\n"
+ "Error:\n{0}".format(e))
raise SeleniumTestError(msg)
diff --git a/yaksh/models.py b/yaksh/models.py
index 2d84622..398f508 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -982,15 +982,17 @@ class AnswerPaper(models.Model):
"""Returns the number of questions left."""
return self.questions_unanswered.count()
- def completed_question(self, question_id):
+ def add_completed_question(self, question_id):
"""
Adds the completed question to the list of answered
questions and returns the next question.
"""
- next_question = self.next_question(question_id)
- self.questions_answered.add(question_id)
+ if question_id not in self.questions_answered.all():
+ self.questions_answered.add(question_id)
self.questions_unanswered.remove(question_id)
- if next_question.id == int(question_id):
+
+ next_question = self.next_question(question_id)
+ if next_question and next_question.id == int(question_id):
return None
return next_question
@@ -999,16 +1001,19 @@ class AnswerPaper(models.Model):
Skips the current question and returns the next sequentially
available question.
"""
+ all_questions = self.questions.all()
unanswered_questions = self.questions_unanswered.all()
- questions = list(unanswered_questions.values_list('id', flat=True))
+ questions = list(all_questions.values_list('id', flat=True))
if len(questions) == 0:
return None
+ if unanswered_questions.count() == 0:
+ return None
try:
index = questions.index(int(question_id))
next_id = questions[index+1]
except (ValueError, IndexError):
next_id = questions[0]
- return unanswered_questions.get(id=next_id)
+ return all_questions.get(id=next_id)
def time_left(self):
"""Return the time remaining for the user in seconds."""
diff --git a/yaksh/templates/exam.html b/yaksh/templates/exam.html
index b497cc0..02ff70a 100644
--- a/yaksh/templates/exam.html
+++ b/yaksh/templates/exam.html
@@ -52,7 +52,9 @@
{% endif %}
{% endif %}
{% if qid in paper.get_questions_answered %}
- <li class="disabled"><a style="background-color:#B4B8BA; width:25%" href="#" data-toggle="tooltip" title="{{ qid.description }}" >{{ forloop.counter }}</a></li>
+ <li><a style="background-color:#B4B8BA; width:25%" href="#" data-toggle="tooltip"
+ onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ paper.question_paper.id }}/')"
+ title="{{ qid.description }}">{{ forloop.counter }}</a></li>
{% endif %}
{% else %}
{% if qid.id == question.id %}
diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html
index 1f6e67d..9dd0de5 100644
--- a/yaksh/templates/yaksh/question.html
+++ b/yaksh/templates/yaksh/question.html
@@ -135,13 +135,25 @@ function call_skip(url)
{% block onload %} onload="updateTime();" {% endblock %}
{% block main %}
- <p id="status"></p>
- <form id="code" action="{{URL_ROOT}}/exam/{{ question.id }}/check/{{ paper.attempt_number }}/{{ paper.question_paper.id }}/" method="post" enctype="multipart/form-data">
- {% csrf_token %}
- <input type=hidden name="question_id" id="question_id" value={{ question.id }}></input>
- <div class="panel panel-default">
- <div class="panel-heading">
- <h4><u> {{ question.summary }}
+ <p id="status"></p>
+ {% if notification %}
+ {% if question.type == "code" %}
+ <div class="alert alert-success" role="alert">
+ <strong>Note:</strong> {{ notification }}
+ </div>
+ {% else %}
+ <div class="alert alert-warning" role="alert">
+ <strong>Note:</strong> {{ notification }}
+ </div>
+ {% endif %}
+ {% endif %}
+ <form id="code" action="{{URL_ROOT}}/exam/{{ question.id }}/check/{{ paper.attempt_number }}/{{ paper.question_paper.id }}/" method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ <input type=hidden name="question_id" id="question_id" value={{ question.id }}></input>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h4>
+ <u> {{ question.summary }}
{% if question.type == "mcq" %}
(Single Correct Choice Questions)
{% elif question.type == "mcc" %}
@@ -151,8 +163,8 @@ function call_skip(url)
{% elif question.type == "upload" %}
(ASSIGNMENT UPLOAD)
{% endif %}
- </u>
- <font class=pull-right>(Marks : {{ question.points }}) </font>
+ </u>
+ <font class=pull-right>(Marks : {{ question.points }}) </font>
</h4>
<font size=3 face=arial> {{ question.description|safe }} </font>
{% if files %}
@@ -198,10 +210,15 @@ function call_skip(url)
{% elif question.type == "upload" %}
<br><button class="btn btn-primary" type="submit" name="check" id="check" onClick="return validate();">Upload</button>&nbsp;&nbsp;
{% else %}
- <button class="btn btn-primary" type="submit" name="check" id="check" onClick="submitCode();">Check Answer <span class="glyphicon glyphicon-cog"></span></button>&nbsp;&nbsp;
+ {% if question in paper.get_questions_unanswered %}
+ <button class="btn btn-primary" type="submit" name="check" id="check" onClick="submitCode();">Check Answer <span class="glyphicon glyphicon-cog"></span></button>&nbsp;&nbsp;
+ {% 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 }}/{{ paper.question_paper.id }}/')" name="skip" id="skip">Attempt Later <span class="glyphicon glyphicon-arrow-right"></span></button>
+ {% endif %}
</div>
</div>
</div>
diff --git a/yaksh/templates/yaksh/user_data.html b/yaksh/templates/yaksh/user_data.html
index 9be28fb..16707b2 100644
--- a/yaksh/templates/yaksh/user_data.html
+++ b/yaksh/templates/yaksh/user_data.html
@@ -100,7 +100,7 @@ User IP address: {{ paper.user_ip }}
{% else %}
<h5>Student answer: </h5>
{% for answer in answers %}
- {% if not answer.skipped %}
+
{% if answer.answer.correct %}
<div class="panel panel-success">
<div class="panel-heading">Correct answer
@@ -116,7 +116,7 @@ User IP address: {{ paper.user_ip }}
</div>
<div class="panel-body"><pre><code>{{ answer.answer.answer.strip }}</code></pre></div>
</div>
- {% endif %}
+
{% endfor %}
{% endif %}
<hr>
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index 91d8806..cd66aed 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -662,7 +662,7 @@ class AnswerPaperTestCases(unittest.TestCase):
current_question = self.answerpaper.current_question()
self.assertEqual(current_question.id, 1)
# Test completed_question() method of Answer Paper
- question = self.answerpaper.completed_question(1)
+ question = self.answerpaper.add_completed_question(1)
self.assertEqual(self.answerpaper.questions_left(), 2)
# Test next_question() method of Answer Paper
@@ -694,7 +694,7 @@ class AnswerPaperTestCases(unittest.TestCase):
# Then
self.assertTrue(next_question_id is not None)
- self.assertEqual(next_question_id.id, 2)
+ self.assertEqual(next_question_id.id, 1)
# Given, last question in the list
current_question_id = 3
@@ -704,7 +704,7 @@ class AnswerPaperTestCases(unittest.TestCase):
# Then
self.assertTrue(next_question_id is not None)
- self.assertEqual(next_question_id.id, 2)
+ self.assertEqual(next_question_id.id, 1)
# Test get_questions_answered() method
# When
@@ -724,14 +724,14 @@ class AnswerPaperTestCases(unittest.TestCase):
# Test completed_question and next_question
# When all questions are answered
- current_question = self.answerpaper.completed_question(2)
+ current_question = self.answerpaper.add_completed_question(2)
# Then
self.assertEqual(self.answerpaper.questions_left(), 1)
self.assertEqual(current_question.id, 3)
# When
- current_question = self.answerpaper.completed_question(3)
+ current_question = self.answerpaper.add_completed_question(3)
# Then
self.assertEqual(self.answerpaper.questions_left(), 0)
diff --git a/yaksh/views.py b/yaksh/views.py
index 74c409c..1089067 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -400,7 +400,7 @@ def start(request, questionpaper_id=None, attempt_num=None):
@login_required
-def show_question(request, question, paper, error_message=None):
+def show_question(request, question, paper, error_message=None, notification=None):
"""Show a question if possible."""
user = request.user
if not question:
@@ -412,10 +412,14 @@ def show_question(request, question, paper, error_message=None):
if paper.time_left() <= 0:
reason='Your time is up!'
return complete(request, reason, paper.attempt_number, paper.question_paper.id)
+ if question in paper.questions_answered.all():
+ notification = 'You have already attempted this question successfully' \
+ if question.type == "code" else \
+ 'You have already attempted this question'
test_cases = question.get_test_cases()
files = FileUpload.objects.filter(question_id=question.id, hide=False)
context = {'question': question, 'paper': paper, 'error_message': error_message,
- 'test_cases': test_cases, 'files': files,
+ 'test_cases': test_cases, 'files': files, 'notification': notification,
'last_attempt': question.snippet.encode('unicode-escape')}
answers = paper.get_previous_answers(question)
if answers:
@@ -432,9 +436,6 @@ def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None):
paper = get_object_or_404(AnswerPaper, user=request.user, attempt_number=attempt_num,
question_paper=questionpaper_id)
question = get_object_or_404(Question, pk=q_id)
- if question in paper.questions_answered.all():
- next_q = paper.next_question(q_id)
- return show_question(request, next_q, paper)
if request.method == 'POST' and question.type == 'code':
user_code = request.POST.get('answer')
@@ -445,8 +446,6 @@ def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None):
paper.answers.add(new_answer)
if next_q is not None:
next_q = get_object_or_404(Question, pk=next_q)
- if next_q not in paper.questions_unanswered.all():
- return show_question(request, question, paper)
else:
next_q = paper.next_question(q_id)
return show_question(request, next_q, paper)
@@ -459,9 +458,6 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
paper = get_object_or_404(AnswerPaper, user=request.user, attempt_number=attempt_num,
question_paper=questionpaper_id)
current_question = get_object_or_404(Question, pk=q_id)
- if current_question in paper.questions_answered.all():
- next_q = paper.next_question(q_id)
- return show_question(request, next_q, paper)
if request.method == 'POST':
snippet_code = request.POST.get('snippet')
@@ -480,14 +476,14 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
assign.assignmentFile = request.FILES['assignment']
assign.save()
user_answer = 'ASSIGNMENT UPLOADED'
- next_q = paper.completed_question(current_question.id)
+ next_q = paper.add_completed_question(current_question.id)
return show_question(request, next_q, paper)
else:
user_code = request.POST.get('answer')
user_answer = snippet_code + "\n" + user_code if snippet_code else user_code
if not user_answer:
msg = ["Please submit a valid option or code"]
- return show_question(request, current_question, paper, msg)
+ return show_question(request, current_question, paper, notification=msg)
new_answer = Answer(question=current_question, answer=user_answer,
correct=False, error=json.dumps([]))
new_answer.save()
@@ -505,15 +501,16 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
new_answer.correct = result.get('success')
error_message = None
new_answer.error = json.dumps(result.get('error'))
- next_question = paper.completed_question(current_question.id)
+ next_question = paper.add_completed_question(current_question.id)
else:
new_answer.marks = (current_question.points * result['weight'] /
current_question.get_maximum_test_case_weight()) \
if current_question.partial_grading and current_question.type == 'code' else 0
- error_message = result.get('error')
+ error_message = result.get('error') if current_question.type == 'code' \
+ else None
new_answer.error = json.dumps(result.get('error'))
next_question = current_question if current_question.type == 'code' \
- else paper.completed_question(current_question.id)
+ else paper.add_completed_question(current_question.id)
new_answer.save()
paper.update_marks('inprogress')
paper.set_end_time(timezone.now())