diff options
author | ankitjavalkar | 2015-05-21 18:41:59 +0530 |
---|---|---|
committer | ankitjavalkar | 2015-06-01 16:33:56 +0530 |
commit | f49b5644b5c4cc2db40d810b3e2b2e4191033c06 (patch) | |
tree | 2e160e2697f7538e8bdf7acf1bd4cd99fa4b9718 /testapp/exam | |
parent | 5ea5324aba75b3d76c2c1d275851d3da06d78d63 (diff) | |
download | online_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
Diffstat (limited to 'testapp/exam')
-rw-r--r-- | testapp/exam/models.py | 53 | ||||
-rw-r--r-- | testapp/exam/templates/exam/complete.html | 27 | ||||
-rw-r--r-- | testapp/exam/templates/exam/question.html | 5 | ||||
-rw-r--r-- | testapp/exam/templates/exam/quit.html | 29 | ||||
-rw-r--r-- | testapp/exam/views.py | 71 | ||||
-rw-r--r-- | testapp/exam/xmlrpc_clients.py | 1 |
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> {% 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> <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> <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 |