summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorankitjavalkar2015-05-21 18:41:59 +0530
committerankitjavalkar2015-06-01 16:33:56 +0530
commitf49b5644b5c4cc2db40d810b3e2b2e4191033c06 (patch)
tree2e160e2697f7538e8bdf7acf1bd4cd99fa4b9718
parent5ea5324aba75b3d76c2c1d275851d3da06d78d63 (diff)
downloadonline_test-f49b5644b5c4cc2db40d810b3e2b2e4191033c06.tar.gz
online_test-f49b5644b5c4cc2db40d810b3e2b2e4191033c06.tar.bz2
online_test-f49b5644b5c4cc2db40d810b3e2b2e4191033c06.zip
Add Multiple Features based on feedback
- Remove Attempt later button on last question - Improve mechanism for cycling through - Add attempt summary on Quit or Completion - Fix error paginator not displaying on error
-rw-r--r--testapp/exam/models.py53
-rw-r--r--testapp/exam/templates/exam/complete.html27
-rw-r--r--testapp/exam/templates/exam/question.html5
-rw-r--r--testapp/exam/templates/exam/quit.html29
-rw-r--r--testapp/exam/views.py71
-rw-r--r--testapp/exam/xmlrpc_clients.py1
6 files changed, 138 insertions, 48 deletions
diff --git a/testapp/exam/models.py b/testapp/exam/models.py
index c5043dc..deb9b2a 100644
--- a/testapp/exam/models.py
+++ b/testapp/exam/models.py
@@ -245,6 +245,8 @@ class QuestionPaper(models.Model):
if self.shuffle_questions:
shuffle(question_ids)
ans_paper.questions = "|".join(question_ids)
+ if not ans_paper.questions_unanswered:
+ ans_paper.questions_unanswered = ans_paper.questions
ans_paper.save()
return ans_paper
@@ -298,6 +300,9 @@ class AnswerPaper(models.Model):
# The questions successfully answered (a list of ids separated by '|')
questions_answered = models.CharField(max_length=128)
+ # The unanswered questions (a list of ids separated by '|')
+ questions_unanswered = models.CharField(max_length=128)
+
# All the submitted answers.
answers = models.ManyToManyField(Answer)
@@ -317,9 +322,14 @@ class AnswerPaper(models.Model):
status = models.CharField(max_length=20, choices=test_status,\
default='inprogress')
+ # def initialise_questions_unanswered(self):
+ # if not self.questions_unanswered:
+ # self.questions_unanswered = self.questions
+ # self.save()
+
def current_question(self):
"""Returns the current active question to display."""
- qs = self.questions.split('|')
+ qs = self.questions_unanswered.split('|')
if len(qs) > 0:
return qs[0]
else:
@@ -327,7 +337,7 @@ class AnswerPaper(models.Model):
def questions_left(self):
"""Returns the number of questions left."""
- qs = self.questions
+ qs = self.questions_unanswered
if len(qs) == 0:
return 0
else:
@@ -343,29 +353,40 @@ class AnswerPaper(models.Model):
self.questions_answered = '|'.join([qa, str(question_id)])
else:
self.questions_answered = str(question_id)
- qs = self.questions.split('|')
- qs.remove(unicode(question_id))
- self.questions = '|'.join(qs)
- self.save()
+ qs = self.questions_unanswered.split('|')
+ try:
+ q_index = qs.index(unicode(question_id))
+ qs.remove(unicode(question_id))
+ self.questions_unanswered = '|'.join(qs) if qs else ""
+ self.save()
+ except ValueError:
+ q_index = qs[0]
if len(qs) == 0:
return ''
else:
- return qs[0]
+ if q_index in range(0, len(qs)-1):
+ return qs[q_index]
+ else:
+ return qs[0]
- def skip(self):
+ def skip(self, question_id):
"""
- Skips the current question and returns the next available question.
+ Skips the current question and returns the next sequentially
+ available question.
"""
- qs = self.questions.split('|')
+ qs = self.questions_unanswered.split('|')
if len(qs) == 0:
return ''
else:
- # Put head at the end.
- head = qs.pop(0)
- qs.append(head)
- self.questions = '|'.join(qs)
- self.save()
- return qs[0]
+ try:
+ q_index = qs.index(unicode(question_id))
+ except ValueError:
+ q_index = qs[0]
+ if q_index in range(0, len(qs)-1):
+ next_q = qs[q_index + 1]
+ else:
+ next_q = qs[0]
+ return next_q
def time_left(self):
"""Return the time remaining for the user in seconds."""
diff --git a/testapp/exam/templates/exam/complete.html b/testapp/exam/templates/exam/complete.html
index 1d5df3c..08abe76 100644
--- a/testapp/exam/templates/exam/complete.html
+++ b/testapp/exam/templates/exam/complete.html
@@ -5,8 +5,29 @@
{% block pagetitle %}Online Test{% endblock %}
{% block content %}
{% csrf_token %}
- <center><h2> Good bye! </h2></center>
- <center><h4> {{message}} </h4></center>
- <center><h4>You may now close the browser.</h4></center><br>
+ {% if submitted or unattempted %}
+ <br><center><table class="bordered-table zebra-striped span8"
+ style="text-align:left;">
+ <tr><td><b>Submitted Questions</b></td>
+ <td>
+ {% if submitted %}
+ {{ submitted|join:", " }}
+ {% else %}
+ <p><b>No Questions have been Submitted</b></p>
+ {% endif %}
+ </td></tr>
+ <tr><td><b>Unattempted Questions</b></td>
+ <td>
+ {% if unattempted %}
+ {{ unattempted|join:", " }}
+ {% else %}
+ <p><b>All Questions have been Submitted</b></p>
+ {% endif %}
+ </td></tr>
+ </table></center>
+ {% endif %}
+ <center><h2> Good bye! </h2></center>
+ <center><h4> {{message}} </h4></center>
+ <br><center><h4>You may now close the browser.</h4></center><br>
<center><a href="{{URL_ROOT}}/exam/"> Login Again </a></center>
{% endblock content %}
diff --git a/testapp/exam/templates/exam/question.html b/testapp/exam/templates/exam/question.html
index 5cc9db0..b7a7053 100644
--- a/testapp/exam/templates/exam/question.html
+++ b/testapp/exam/templates/exam/question.html
@@ -104,7 +104,6 @@ function call_skip(url)
</div>
</div>
</div>
-
<div class = container>
<div class="sidebar">
<p>Question Navigator </p>
@@ -179,7 +178,9 @@ function call_skip(url)
{% else %}
<button class="btn" type="submit" name="check" id="check" onClick="submitCode();">Check Answer</button>&nbsp;&nbsp;
{% endif %}
- <button class="btn" type="submit" name="skip" id="skip">Attempt Later</button>
+ {% if to_attempt|length != 1 %}
+ <button class="btn" type="submit" name="skip" id="skip">Attempt Later</button>
+ {% endif %}
</form>
diff --git a/testapp/exam/templates/exam/quit.html b/testapp/exam/templates/exam/quit.html
index f49b62f..91bce64 100644
--- a/testapp/exam/templates/exam/quit.html
+++ b/testapp/exam/templates/exam/quit.html
@@ -3,12 +3,33 @@
{% block title %}Quit exam {% endblock %}
{% block pagetitle %}Online Test {% endblock %}
{% block content %}
+ {% if submitted or unattempted %}
+ <br><center><table class="bordered-table zebra-striped span8"
+ style="text-align:left;">
+ <tr><td><b>Submitted Questions</b></td>
+ <td>
+ {% if submitted %}
+ {{ submitted|join:", " }}
+ {% else %}
+ <p><b>No Questions have been Submitted</b></p>
+ {% endif %}
+ </td></tr>
+ <tr><td><b>Unattempted Questions</b></td>
+ <td>
+ {% if unattempted %}
+ {{ unattempted|join:", " }}
+ {% else %}
+ <p><b>All Questions have been Submitted</b></p>
+ {% endif %}
+ </td></tr>
+ </table></center>
+ {% endif %}
- <center><h4>Your current answers are saved.</h4></center>
+ <center><h4>Your current answers are saved.</h4></center>
<center><h4> Are you sure you wish to quit the exam?</h4></center>
- <center><h4> Be sure, as you won't be able to restart this exam.</h4></center>
- <form action="{{URL_ROOT}}/exam/complete/{{ attempt_num }}/{{ id }}/" method="post">
+ <center><h4> Be sure, as you won't be able to restart this exam.</h4></center>
+ <form action="{{URL_ROOT}}/exam/complete/{{ attempt_num }}/{{ id }}/" method="post">
{% csrf_token %}
- <center><button class="btn" type="submit" name="yes">Yes!</button>&nbsp;<button class="btn" type="button" name="no" onClick="window.location='{{ URL_ROOT }}/exam/start/{{ attempt_num }}/{{ id }}/'">No!</button></center>
+ <center><button class="btn" type="submit" name="yes">Yes!</button>&nbsp;<button class="btn" type="button" name="no" onClick="window.location='{{ URL_ROOT }}/exam/start/{{ attempt_num }}/{{ id }}/'">No!</button></center>
</form>
{% endblock content %}
diff --git a/testapp/exam/views.py b/testapp/exam/views.py
index 0ca404d..fc29df1 100644
--- a/testapp/exam/views.py
+++ b/testapp/exam/views.py
@@ -803,22 +803,18 @@ def get_questions(paper):
all_questions = []
questions = {}
if paper.questions:
- to_attempt = (paper.questions).split('|')
+ all_questions = (paper.questions).split('|')
if paper.questions_answered:
- submitted = (paper.questions_answered).split('|')
- if not to_attempt:
- submitted.sort()
- all_questions = submitted
- if not submitted:
- to_attempt.sort()
- all_questions = to_attempt
- if to_attempt and submitted:
- q_append = to_attempt + submitted
- q_append.sort()
- all_questions = q_append
- for num, value in enumerate(all_questions, 1):
- questions[value] = num
- questions = collections.OrderedDict(sorted(questions.items()))
+ q_answered = (paper.questions_answered).split('|')
+ q_answered.sort()
+ submitted = q_answered
+ if paper.questions_unanswered:
+ q_unanswered = (paper.questions_unanswered).split('|')
+ q_unanswered.sort()
+ to_attempt = (paper.questions_unanswered).split('|')
+ for index, value in enumerate(all_questions, 1):
+ questions[value] = index
+ questions = collections.OrderedDict(sorted(questions.items(), key=lambda x:x[1]))
return questions, to_attempt, submitted
@@ -909,7 +905,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
paper = AnswerPaper.objects.get(user=request.user, attempt_number=attempt_num,
question_paper=q_paper)
if q_id in paper.questions_answered:
- next_q = paper.skip()
+ next_q = paper.skip(q_id)
return show_question(request, next_q, attempt_num, questionpaper_id)
if not user.is_authenticated() or paper.end_time < datetime.datetime.now():
@@ -927,7 +923,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
if question.type == 'code':
old_skipped = paper.answers.filter(question=question, skipped=True)
_save_skipped_answer(old_skipped, user_code, paper, question)
- next_q = paper.skip()
+ next_q = paper.skip(q_id)
return show_question(request, next_q, attempt_num, questionpaper_id)
# Add the answer submitted, regardless of it being correct or not.
@@ -989,8 +985,8 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
context = {'question': question, 'error_message': result.get('error'),
'paper': paper, 'last_attempt': user_code,
'quiz_name': paper.question_paper.quiz.description,
- 'time_left': time_left, 'to_attempt': to_attempt,
- 'submitted': submitted}
+ 'time_left': time_left, 'questions': questions,
+ 'to_attempt': to_attempt, 'submitted': submitted}
ci = RequestContext(request)
return my_render_to_response('exam/question.html', context,
@@ -1037,11 +1033,34 @@ def validate_answer(user, user_answer, question, json_data=None):
return correct, result
+def get_question_labels(request, attempt_num=None, questionpaper_id=None):
+ """Get the question number show in template for corresponding
+ question id."""
+ unattempted_questions = []
+ submitted_questions = []
+ try:
+ q_paper = QuestionPaper.objects.get(id=questionpaper_id)
+ paper = AnswerPaper.objects.get(
+ user=request.user, attempt_number=attempt_num, question_paper=q_paper)
+ except AnswerPaper.DoesNotExist:
+ return my_redirect('/exam/start/')
+ questions, to_attempt, submitted = get_questions(paper)
+ for q_id, question_label in questions.items():
+ if q_id in to_attempt:
+ unattempted_questions.append(question_label)
+ else:
+ submitted_questions.append(question_label)
+ unattempted_questions.sort()
+ submitted_questions.sort()
+ return unattempted_questions, submitted_questions
def quit(request, attempt_num=None, questionpaper_id=None):
"""Show the quit page when the user logs out."""
- context = {'id': questionpaper_id,
- 'attempt_num': attempt_num}
+ unattempted_questions, submitted_questions = get_question_labels(request,
+ attempt_num, questionpaper_id)
+ context = {'id': questionpaper_id, 'attempt_num': attempt_num,
+ 'unattempted': unattempted_questions,
+ 'submitted': submitted_questions}
return my_render_to_response('exam/quit.html', context,
context_instance=RequestContext(request))
@@ -1056,6 +1075,8 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None):
context = {'message': message}
return my_render_to_response('exam/complete.html', context)
else:
+ unattempted_questions, submitted_questions = get_question_labels(request,
+ attempt_num, questionpaper_id)
q_paper = QuestionPaper.objects.get(id=questionpaper_id)
paper = AnswerPaper.objects.get(user=user, question_paper=q_paper,
attempt_number=attempt_num)
@@ -1071,11 +1092,15 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None):
context = {'message': "Hurray ! You did an excellent job.\
you answered all the questions correctly.\
You have been logged out successfully,\
- Thank You !"}
+ Thank You !",
+ 'unattempted': unattempted_questions,
+ 'submitted': submitted_questions}
return my_render_to_response('exam/complete.html', context)
else:
message = reason or "You are successfully logged out"
- context = {'message': message}
+ context = {'message': message,
+ 'unattempted': unattempted_questions,
+ 'submitted': submitted_questions}
return my_render_to_response('exam/complete.html', context)
no = False
message = reason or 'The quiz has been completed. Thank you.'
diff --git a/testapp/exam/xmlrpc_clients.py b/testapp/exam/xmlrpc_clients.py
index 8f5642e..3a3c0c6 100644
--- a/testapp/exam/xmlrpc_clients.py
+++ b/testapp/exam/xmlrpc_clients.py
@@ -2,6 +2,7 @@ from xmlrpclib import ServerProxy
import time
import random
import socket
+import json
from settings import SERVER_PORTS, SERVER_POOL_PORT