diff options
author | prathamesh | 2015-04-07 13:39:47 +0530 |
---|---|---|
committer | prathamesh | 2015-04-07 13:39:47 +0530 |
commit | bd5b1e21c4d837dab410f9a3eb332d7af3d0185a (patch) | |
tree | 99b4fb8ff258fe8ed496dd7100a0c5e23b6e7319 /testapp | |
parent | 28415b148617057674d85aee9a2d3aaac36bf0d2 (diff) | |
download | online_test-bd5b1e21c4d837dab410f9a3eb332d7af3d0185a.tar.gz online_test-bd5b1e21c4d837dab410f9a3eb332d7af3d0185a.tar.bz2 online_test-bd5b1e21c4d837dab410f9a3eb332d7af3d0185a.zip |
Multiple attempts and file upload question type.
Can have multiple attempts for a quiz.
Can also specify time lag between two successive attempts for a given
quiz.
Students can upload their code through the interface.
The code will be saved in the folder named after their roll number.
And the file name will be the question id.
Diffstat (limited to 'testapp')
-rw-r--r-- | testapp/exam/forms.py | 16 | ||||
-rw-r--r-- | testapp/exam/models.py | 47 | ||||
-rw-r--r-- | testapp/exam/templates/exam/intro.html | 2 | ||||
-rw-r--r-- | testapp/exam/templates/exam/question.html | 49 | ||||
-rw-r--r-- | testapp/exam/templates/exam/quit.html | 4 | ||||
-rw-r--r-- | testapp/exam/urls.py | 33 | ||||
-rw-r--r-- | testapp/exam/views.py | 141 |
7 files changed, 203 insertions, 89 deletions
diff --git a/testapp/exam/forms.py b/testapp/exam/forms.py index f04fdb3..1f12a3b 100644 --- a/testapp/exam/forms.py +++ b/testapp/exam/forms.py @@ -27,11 +27,17 @@ question_types = ( ("mcq", "Multiple Choice"), ("mcc", "Multiple Correct Choices"), ("code", "Code"), + ("upload", "Assignment Upload"), ) UNAME_CHARS = letters + "._" + digits PWD_CHARS = letters + punctuation + digits +attempts = [(i, i) for i in range(1, 6)] +attempts.append((-1, 'Infinite')) +days_between_attempts = ((j, j) for j in range(401)) + + class UserRegisterForm(forms.Form): """A Class to create new form for User's Registration. It has the various fields and functions required to register @@ -131,7 +137,7 @@ class QuizForm(forms.Form): super(QuizForm, self).__init__(*args, **kwargs) quizzes = [('', 'Select a prerequisite quiz')] quizzes = quizzes + \ - list(Quiz.objects.values_list('id','description')) + list(Quiz.objects.values_list('id', 'description')) self.fields['prerequisite'] = forms.CharField(required=False, widget=forms.Select(choices=quizzes)) @@ -143,6 +149,10 @@ class QuizForm(forms.Form): pass_criteria = forms.FloatField(initial=40, help_text='Will be taken as percentage') language = forms.CharField(widget=forms.Select(choices=languages)) + attempts_allowed = forms.IntegerField(widget=forms.Select(choices=attempts)) + time_between_attempts = forms.IntegerField\ + (widget=forms.Select(choices=days_between_attempts), + help_text='Will be in days') def save(self): start_date = self.cleaned_data["start_date"] @@ -152,6 +162,8 @@ class QuizForm(forms.Form): pass_criteria = self.cleaned_data["pass_criteria"] language = self.cleaned_data["language"] prerequisite = self.cleaned_data["prerequisite"] + attempts_allowed = self.cleaned_data["attempts_allowed"] + time_between_attempts = self.cleaned_data["time_between_attempts"] new_quiz = Quiz() new_quiz.start_date = start_date new_quiz.duration = duration @@ -160,6 +172,8 @@ class QuizForm(forms.Form): new_quiz.pass_criteria = pass_criteria new_quiz.language = language new_quiz.prerequisite_id = prerequisite + new_quiz.attempts_allowed = attempts_allowed + new_quiz.time_between_attempts = time_between_attempts new_quiz.save() diff --git a/testapp/exam/models.py b/testapp/exam/models.py index 196ee73..24ec10b 100644 --- a/testapp/exam/models.py +++ b/testapp/exam/models.py @@ -30,7 +30,20 @@ question_types = ( ("mcq", "Multiple Choice"), ("mcc", "Multiple Correct Choices"), ("code", "Code"), + ("upload", "Assignment Upload"), ) +attempts = [(i, i) for i in range(1, 6)] +attempts.append((-1, 'Infinite')) +days_between_attempts = ((j, j) for j in range(401)) + +test_status = ( + ('inprogress', 'Inprogress'), + ('completed', 'Completed'), + ) + + +def get_assignment_dir(instance, filename): + return '%s/%s' % (instance.user.roll_number, instance.assignmentQuestion.id) ############################################################################### @@ -125,6 +138,12 @@ class Quiz(models.Model): # Programming language for a quiz language = models.CharField(max_length=20, choices=languages) + # Number of attempts for the quiz + attempts_allowed = models.IntegerField(default=1, choices=attempts) + + time_between_attempts = models.IntegerField("Number of Days",\ + choices=days_between_attempts) + class Meta: verbose_name_plural = "Quizzes" @@ -171,9 +190,9 @@ class QuestionPaper(models.Model): questions += question_set.get_random_questions() return questions - def make_answerpaper(self, user, ip): + def make_answerpaper(self, user, ip, attempt_no): """Creates an answer paper for the user to attempt the quiz""" - ans_paper = AnswerPaper(user=user, profile=user.profile, user_ip=ip) + ans_paper = AnswerPaper(user=user, user_ip=ip, attempt_number=attempt_no) ans_paper.start_time = datetime.datetime.now() ans_paper.end_time = ans_paper.start_time \ + datetime.timedelta(minutes=self.quiz.duration) @@ -214,10 +233,6 @@ class AnswerPaper(models.Model): # The user taking this question paper. user = models.ForeignKey(User) - # The user's profile, we store a reference to make it easier to access the - # data. - profile = models.ForeignKey(Profile) - # All questions that remain to be attempted for a particular Student # (a list of ids separated by '|') questions = models.CharField(max_length=128) @@ -225,6 +240,9 @@ class AnswerPaper(models.Model): # The Quiz to which this question paper is attached to. question_paper = models.ForeignKey(QuestionPaper) + # The attempt number for the question paper. + attempt_number = models.IntegerField() + # The time when this paper was started by the user. start_time = models.DateTimeField() @@ -252,6 +270,10 @@ class AnswerPaper(models.Model): # Result of the quiz, True if student passes the exam. passed = models.NullBooleanField() + # Status of the quiz attempt + status = models.CharField(max_length=20, choices=test_status,\ + default='inprogress') + def current_question(self): """Returns the current active question to display.""" qs = self.questions.split('|') @@ -337,12 +359,16 @@ class AnswerPaper(models.Model): Checks whether student passed or failed, as per the quiz passing criteria. """ - if self.percent is not None: + if self.percent is not None: if self.percent >= self.question_paper.quiz.pass_criteria: self.passed = True else: self.passed = False + def update_status(self): + """ Sets status to completed """ + self.status = 'completed' + def get_question_answers(self): """ Return a dictionary with keys as questions and a list of the @@ -360,3 +386,10 @@ class AnswerPaper(models.Model): def __unicode__(self): u = self.user return u'Question paper for {0} {1}'.format(u.first_name, u.last_name) + + +############################################################################### +class AssignmentUpload(models.Model): + user = models.ForeignKey(Profile) + assignmentQuestion = models.ForeignKey(Question) + assignmentFile = models.FileField(upload_to=get_assignment_dir) diff --git a/testapp/exam/templates/exam/intro.html b/testapp/exam/templates/exam/intro.html index ec1888a..58068ed 100644 --- a/testapp/exam/templates/exam/intro.html +++ b/testapp/exam/templates/exam/intro.html @@ -27,7 +27,7 @@ </ul> <p> We hope you enjoy taking this exam !!!</p> - <form action="{{URL_ROOT}}/exam/start/{{ paper_id }}/" method="post" align="center"> + <form action="{{URL_ROOT}}/exam/start/{{ attempt_no }}/{{ paper_id }}/" method="post" align="center"> {% csrf_token %} <center><button class="btn" type="submit" name="start">Start Exam!</button></center> </form> diff --git a/testapp/exam/templates/exam/question.html b/testapp/exam/templates/exam/question.html index a3e8629..977b388 100644 --- a/testapp/exam/templates/exam/question.html +++ b/testapp/exam/templates/exam/question.html @@ -10,7 +10,10 @@ {% endblock %} {% block script %} +<script src="/static/taggit_autocomplete_modified/jquery.min.js" type="text/javascript"></script> +<script src="/static/taggit_autocomplete_modified/jquery.autocomplete.js" type="text/javascript"></script> <script src="{{ URL_ROOT }}/static/exam/js/question.js"></script> +<script src="{{ URL_ROOT }}/static/exam/js/bootstrap-modal.js"></script> <script> var time_left = {{ time_left }} @@ -49,6 +52,18 @@ function setSnippetHeight() autoresize(); } +function validate(){ + uploaded_file = document.getElementById("assignment").value; + if(uploaded_file == ""){ + $("#upload_alert").modal("show"); + return false; + } + else + { + return true; + } +} + </script> {% endblock script %} @@ -74,7 +89,7 @@ function setSnippetHeight() <ul> <li> <h5><a> Hi {{user.first_name.title}} {{user.last_name.title}} </a></h5> </ul> - <form id="logout" action="{{URL_ROOT}}/exam/quit/{{ paper.question_paper.id }}/" method="post" class="pull-right"> + <form id="logout" action="{{URL_ROOT}}/exam/quit/{{ paper.attempt_number }}/{{ paper.question_paper.id }}/" method="post" class="pull-right"> {% csrf_token %} <button class="btn" type="submit" name="quit">Quit Exam</button> </li> @@ -94,19 +109,20 @@ function setSnippetHeight() {% endfor%} </div>{% endif %} - {% if success_msg %} - <script type="text/javascript"> - alert("Congratulations, that's correct. Let's go to next question"); - </script> - {% endif %} <p id="status"></p> - <form id="code" action="{{URL_ROOT}}/exam/{{ question.id }}/check/{{ paper.question_paper.id }}/" method="post"> + + <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 %} {% if question.type == "mcq" %} {% for option in question.options.strip.splitlines %} <input name="answer" type="radio" value="{{option}}" />{{option}} <br/> {% endfor %} {% endif %} + {% if question.type == "upload" %} + <p>Upload assignment file for the said question<p> + <input type=file id="assignment" name="assignment"> + <hr> + {% endif %} {% if question.type == "mcc" %} {% for option in question.options.strip.splitlines %} <input name="answer" type="checkbox" value="{{ option }}"> {{ option }} @@ -128,6 +144,8 @@ function setSnippetHeight() {% if question.type == "mcq" or question.type == "mcc "%} <br><button class="btn" type="submit" name="check" id="check">Submit Answer</button> + {% elif question.type == "upload" %} + <br><button class="btn" type="submit" name="check" id="check" onClick="return validate();">Upload</button> {% else %} <button class="btn" type="submit" name="check" id="check" onClick="submitCode();">Check Answer</button> {% endif %} @@ -135,4 +153,21 @@ function setSnippetHeight() </form> + <!-- Modal --> + <div class="modal fade " id="upload_alert" > + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="myModalLabel">File not selected</h4> + </div> + <div id = "modal_body"class="modal-body"> + <font color="brown"><b>Kindly attach a file and then click upload.</b></font> + </div> + <div class="modal-footer"> + <button type="button" class="btn primary close" data-dismiss="modal">OK</button> + </div> + </div> + </div> + </div> + {% endblock content %} diff --git a/testapp/exam/templates/exam/quit.html b/testapp/exam/templates/exam/quit.html index fee11ed..2c347cb 100644 --- a/testapp/exam/templates/exam/quit.html +++ b/testapp/exam/templates/exam/quit.html @@ -7,8 +7,8 @@ <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/{{ id }}/" method="post"> + <form action="{{URL_ROOT}}/exam/complete/{{ attempt_no }}/{{ 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/{{ 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_no }}/{{ id }}/'">No!</button></center> </form> {% endblock content %} diff --git a/testapp/exam/urls.py b/testapp/exam/urls.py index f8a6cb8..5ffb588 100644 --- a/testapp/exam/urls.py +++ b/testapp/exam/urls.py @@ -1,21 +1,24 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import patterns, url urlpatterns = patterns('testapp.exam.views', url(r'^$', 'index'), url(r'^login/$', 'user_login'), - url(r'^quizzes/$','quizlist_user'), - url(r'^results/$','results_user'), + url(r'^quizzes/$', 'quizlist_user'), + url(r'^results/$', 'results_user'), url(r'^start/$', 'start'), - url(r'^start/(?P<questionpaper_id>\d+)/$','start'), - url(r'^quit/(?P<questionpaper_id>\d+)/$', 'quit'), - url(r'^intro/(?P<questionpaper_id>\d+)/$','intro'), + url(r'^start/(?P<attempt_no>\d+)/(?P<questionpaper_id>\d+)/$', 'start'), + url(r'^quit/(?P<attempt_no>\d+)/(?P<questionpaper_id>\d+)/$', 'quit'), + url(r'^intro/(?P<questionpaper_id>\d+)/$', 'intro'), url(r'^complete/$', 'complete'), - url(r'^complete/(?P<questionpaper_id>\d+)/$', 'complete'), + url(r'^complete/(?P<attempt_no>\d+)/(?P<questionpaper_id>\d+)/$',\ + 'complete'), url(r'^register/$', 'user_register'), url(r'^(?P<q_id>\d+)/$', 'question'), url(r'^(?P<q_id>\d+)/check/$', 'check'), - url(r'^(?P<q_id>\d+)/check/(?P<questionpaper_id>\d+)/$', 'check'), + url(r'^(?P<q_id>\d+)/check/(?P<attempt_no>\d+)/(?P<questionpaper_id>\d+)/$',\ + 'check'), url(r'^intro/$', 'start'), + url(r'^up/$', 'updation'), url(r'^manage/$', 'prof_manage'), url(r'^manage/addquestion/$', 'add_question'), @@ -25,22 +28,22 @@ urlpatterns = patterns('testapp.exam.views', url(r'^manage/editquestion/$', 'edit_question'), url(r'^manage/addquiz/(?P<quiz_id>\d+)/$', 'add_quiz'), url(r'^manage/gradeuser/$', 'show_all_users'), - url(r'^manage/gradeuser/(?P<username>[a-zA-Z0-9_.]+)/$', 'grade_user'), + url(r'^manage/gradeuser/(?P<username>.*/$', 'grade_user'), url(r'^manage/questions/$', 'show_all_questions'), - url(r'^manage/showquiz/$','show_all_quiz'), + url(r'^manage/showquiz/$', 'show_all_quiz'), url(r'^manage/monitor/$', 'monitor'), - url(r'^manage/showquestionpapers/$','show_all_questionpapers'), + url(r'^manage/showquestionpapers/$', 'show_all_questionpapers'), url(r'^manage/showquestionpapers/(?P<questionpaper_id>\d+)/$',\ 'show_all_questionpapers'), url(r'^manage/monitor/(?P<questionpaper_id>\d+)/$', 'monitor'), - url(r'^manage/user_data/(?P<username>[a-zA-Z0-9_.]+)/$','user_data'), - url(r'^manage/designquestionpaper/$','design_questionpaper'), + url(r'^manage/user_data/(?P<username>.*)/$', 'user_data'), + url(r'^manage/designquestionpaper/$', 'design_questionpaper'), url(r'^manage/designquestionpaper/(?P<questionpaper_id>\d+)/$',\ 'design_questionpaper'), url(r'^manage/designquestionpaper/automatic/(?P<questionpaper_id>\d+)/$',\ 'automatic_questionpaper'), - url(r'^manage/designquestionpaper/automatic$','automatic_questionpaper'), - url(r'^manage/designquestionpaper/manual$','manual_questionpaper'), + url(r'^manage/designquestionpaper/automatic$', 'automatic_questionpaper'), + url(r'^manage/designquestionpaper/manual$', 'manual_questionpaper'), url(r'^manage/designquestionpaper/manual/(?P<questionpaper_id>\d+)/$',\ 'manual_questionpaper'), url(r'^ajax/questionpaper/(?P<query>.+)/$', 'ajax_questionpaper'), diff --git a/testapp/exam/views.py b/testapp/exam/views.py index 474fa2f..d307be7 100644 --- a/testapp/exam/views.py +++ b/testapp/exam/views.py @@ -21,7 +21,7 @@ from testapp.exam.forms import UserRegisterForm, UserLoginForm, QuizForm,\ QuestionForm, RandomQuestionForm from testapp.exam.xmlrpc_clients import code_server from settings import URL_ROOT - +from testapp.exam.models import AssignmentUpload # The directory where user data can be saved. OUTPUT_DIR = abspath(join(dirname(__file__), 'output')) @@ -139,7 +139,7 @@ def quizlist_user(request): user = request.user avail_quizzes = list(QuestionPaper.objects.filter(quiz__active=True)) user_answerpapers = AnswerPaper.objects.filter(user=user) - quizzes_taken = [] + quizzes_taken = user_answerpapers pre_requisites = [] context = {} @@ -152,13 +152,6 @@ def quizlist_user(request): context['quizzes_taken'] = None return my_render_to_response("exam/quizzes_user.html", context) - for answer_paper in user_answerpapers: - for quiz in avail_quizzes: - if answer_paper.question_paper.id == quiz.id and \ - answer_paper.end_time != answer_paper.start_time: - avail_quizzes.remove(quiz) - quizzes_taken.append(answer_paper) - context['quizzes'] = avail_quizzes context['user'] = user context['quizzes_taken'] = quizzes_taken @@ -170,27 +163,45 @@ def intro(request, questionpaper_id): user = request.user ci = RequestContext(request) quest_paper = QuestionPaper.objects.get(id=questionpaper_id) + attempt_number = quest_paper.quiz.attempts_allowed + time_lag = quest_paper.quiz.time_between_attempts + if quest_paper.quiz.prerequisite: try: - pre_quest = QuestionPaper.objects.get(quiz=quest_paper.quiz.prerequisite) - answer_paper = AnswerPaper.objects.get( - question_paper=pre_quest, - user=user) - if answer_paper.passed: - context = {'user': user, 'paper_id': questionpaper_id} - return my_render_to_response('exam/intro.html', context, - context_instance=ci) - else: + pre_quest = QuestionPaper.objects.get( + quiz=quest_paper.quiz.prerequisite) + answer_papers = AnswerPaper.objects.filter( + question_paper=pre_quest, user=user) + answer_papers_failed = AnswerPaper.objects.filter( + question_paper=pre_quest, user=user, passed=False) + if answer_papers.count() == answer_papers_failed.count(): context = {'user': user, 'cannot_attempt': True} return my_redirect("/exam/quizzes/?cannot_attempt=True") - except: context = {'user': user, 'cannot_attempt': True} return my_redirect("/exam/quizzes/?cannot_attempt=True") - context = {'user': user, 'paper_id': questionpaper_id} - ci = RequestContext(request) - return my_render_to_response('exam/intro.html', context, - context_instance=ci) + + attempted_papers = AnswerPaper.objects.filter(question_paper=quest_paper, + user=user) + already_attempted = attempted_papers.count() + if already_attempted == 0: + context = {'user': user, 'paper_id': questionpaper_id,\ + 'attempt_no': already_attempted + 1} + return my_render_to_response('exam/intro.html', context, + context_instance=ci) + if already_attempted < attempt_number or attempt_number < 0: + previous_attempt_day = attempted_papers[already_attempted-1].start_time + today = datetime.datetime.today() + days_after_attempt = (today - previous_attempt_day).days + if days_after_attempt >= time_lag: + context = {'user': user, 'paper_id': questionpaper_id,\ + 'attempt_no': already_attempted + 1} + return my_render_to_response('exam/intro.html', context, + context_instance=ci) + else: + return my_redirect("/exam/quizzes/") + else: + return my_redirect("/exam/quizzes/") def results_user(request): @@ -367,6 +378,8 @@ def add_quiz(request, quiz_id=None): d.pass_criteria = form['pass_criteria'].data d.language = form['language'].data d.prerequisite_id = form['prerequisite'].data + d.attempts_allowed = form['attempts_allowed'].data + d.time_between_attempts = form['time_between_attempts'].data d.save() quiz = Quiz.objects.get(id=quiz_id) return my_redirect("/exam/manage/showquiz") @@ -390,6 +403,8 @@ def add_quiz(request, quiz_id=None): form.initial['pass_criteria'] = d.pass_criteria form.initial['language'] = d.language form.initial['prerequisite'] = d.prerequisite_id + form.initial['attempts_allowed'] = d.attempts_allowed + form.initial['time_between_attempts'] = d.time_between_attempts return my_render_to_response('exam/add_quiz.html', {'form': form}, context_instance=ci) @@ -603,8 +618,10 @@ rights/permissions and log in.""" users_per_paper = [] for paper in question_papers: answer_papers = AnswerPaper.objects.filter(question_paper=paper) - users_passed = AnswerPaper.objects.filter(question_paper=paper, passed=True).count() - users_failed = AnswerPaper.objects.filter(question_paper=paper, passed=False).count() + users_passed = AnswerPaper.objects.filter(question_paper=paper, + passed=True).count() + users_failed = AnswerPaper.objects.filter(question_paper=paper, + passed=False).count() temp = paper, answer_papers, users_passed, users_failed users_per_paper.append(temp) context = {'user': user, 'users_per_paper': users_per_paper} @@ -641,7 +658,7 @@ def user_login(request): context_instance=ci) -def start(request, questionpaper_id=None): +def start(request, attempt_no=None, questionpaper_id=None): """Check the user cedentials and if any quiz is available, start the exam.""" user = request.user @@ -654,13 +671,13 @@ def start(request, questionpaper_id=None): except QuestionPaper.DoesNotExist: msg = 'Quiz not found, please contact your '\ 'instructor/administrator. Please login again thereafter.' - return complete(request, msg, questionpaper_id) + return complete(request, msg, attempt_no, questionpaper_id) try: old_paper = AnswerPaper.objects.get( - question_paper=questionpaper, user=user) + question_paper=questionpaper, user=user, attempt_number=attempt_no) q = old_paper.current_question() - return show_question(request, q, questionpaper_id) + return show_question(request, q, attempt_no, questionpaper_id) except AnswerPaper.DoesNotExist: ip = request.META['REMOTE_ADDR'] key = gen_key(10) @@ -670,13 +687,13 @@ def start(request, questionpaper_id=None): msg = 'You do not have a profile and cannot take the quiz!' raise Http404(msg) - new_paper = questionpaper.make_answerpaper(user, ip,) + new_paper = questionpaper.make_answerpaper(user, ip, attempt_no) # Make user directory. user_dir = get_user_dir(user) - return start(request, questionpaper_id) + return start(request, attempt_no, questionpaper_id) -def question(request, q_id, questionpaper_id, success_msg=None): +def question(request, q_id, attempt_no, questionpaper_id, success_msg=None): """Check the credentials of the user and start the exam.""" user = request.user @@ -686,7 +703,7 @@ def question(request, q_id, questionpaper_id, success_msg=None): try: q_paper = QuestionPaper.objects.get(id=questionpaper_id) paper = AnswerPaper.objects.get( - user=request.user, question_paper=q_paper) + user=request.user, attempt_number=attempt_no, question_paper=q_paper) except AnswerPaper.DoesNotExist: return my_redirect('/exam/start/') if not paper.question_paper.quiz.active: @@ -713,21 +730,22 @@ def question(request, q_id, questionpaper_id, success_msg=None): context_instance=ci) -def show_question(request, q_id, questionpaper_id, success_msg=None): +def show_question(request, q_id, attempt_no, questionpaper_id, success_msg=None): """Show a question if possible.""" if len(q_id) == 0: msg = 'Congratulations! You have successfully completed the quiz.' - return complete(request, msg, questionpaper_id) + return complete(request, msg, attempt_no, questionpaper_id) else: - return question(request, q_id, questionpaper_id, success_msg) + return question(request, q_id, attempt_no, questionpaper_id, success_msg) -def check(request, q_id, questionpaper_id=None): +def check(request, q_id, attempt_no=None, questionpaper_id=None): """Checks the answers of the user for particular question""" user = request.user q_paper = QuestionPaper.objects.get(id=questionpaper_id) - paper = AnswerPaper.objects.get(user=request.user, question_paper=q_paper) + paper = AnswerPaper.objects.get(user=request.user, attempt_number=attempt_no, + question_paper=q_paper) if not user.is_authenticated() or paper.end_time < datetime.datetime.now(): return my_redirect('/exam/login/') question = get_object_or_404(Question, pk=q_id) @@ -737,13 +755,20 @@ def check(request, q_id, questionpaper_id=None): success = True if skip is not None: next_q = paper.skip() - return show_question(request, next_q, questionpaper_id) + return show_question(request, next_q, attempt_no, questionpaper_id) # Add the answer submitted, regardless of it being correct or not. if question.type == 'mcq': user_answer = request.POST.get('answer') elif question.type == 'mcc': user_answer = request.POST.getlist('answer') + elif question.type == 'upload': + assign = AssignmentUpload() + assign.user = user.profile + assign.assignmentQuestion = question + assign.assignmentFile = request.FILES['assignment'] + assign.save() + user_answer = 'ASSIGNMENT UPLOADED' else: user_code = request.POST.get('answer') user_answer = snippet_code + "\n" + user_code @@ -756,24 +781,25 @@ def check(request, q_id, questionpaper_id=None): # If we were not skipped, we were asked to check. For any non-mcq # questions, we obtain the results via XML-RPC with the code executed # safely in a separate process (the code_server.py) running as nobody. - correct, success, err_msg = validate_answer(user, user_answer, question) - if correct: - new_answer.correct = correct - new_answer.marks = question.points - new_answer.error = err_msg - success_msg = True - else: - new_answer.error = err_msg - new_answer.save() + if not question.type == 'upload': + correct, success, err_msg = validate_answer(user, user_answer, question) + if correct: + new_answer.correct = correct + new_answer.marks = question.points + new_answer.error = err_msg + success_msg = True + else: + new_answer.error = err_msg + new_answer.save() time_left = paper.time_left() if not success: # Should only happen for non-mcq questions. if time_left == 0: reason = 'Your time is up!' - return complete(request, reason, questionpaper_id) + return complete(request, reason, attempt_no, questionpaper_id) if not paper.question_paper.quiz.active: reason = 'The quiz has been deactivated!' - return complete(request, reason, questionpaper_id) + return complete(request, reason, attempt_no, questionpaper_id) context = {'question': question, 'error_message': err_msg, 'paper': paper, 'last_attempt': user_code, 'quiz_name': paper.question_paper.quiz.description, @@ -785,10 +811,10 @@ def check(request, q_id, questionpaper_id=None): else: if time_left <= 0: reason = 'Your time is up!' - return complete(request, reason, questionpaper_id) + return complete(request, reason, attempt_no, questionpaper_id) else: next_q = paper.completed_question(question.id) - return show_question(request, next_q, + return show_question(request, next_q, attempt_no, questionpaper_id, success_msg) @@ -824,14 +850,15 @@ def validate_answer(user, user_answer, question): return correct, success, message -def quit(request, questionpaper_id=None): +def quit(request, attempt_no=None, questionpaper_id=None): """Show the quit page when the user logs out.""" - context = {'id': questionpaper_id} + context = {'id': questionpaper_id, + 'attempt_no': attempt_no} return my_render_to_response('exam/quit.html', context, context_instance=RequestContext(request)) -def complete(request, reason=None, questionpaper_id=None): +def complete(request, reason=None, attempt_no=None, questionpaper_id=None): """Show a page to inform user that the quiz has been compeleted.""" user = request.user @@ -842,11 +869,13 @@ def complete(request, reason=None, questionpaper_id=None): return my_render_to_response('exam/complete.html', context) else: q_paper = QuestionPaper.objects.get(id=questionpaper_id) - paper = AnswerPaper.objects.get(user=user, question_paper=q_paper) + paper = AnswerPaper.objects.get(user=user, question_paper=q_paper, + attempt_number=attempt_no) paper.update_marks_obtained() paper.update_percent() paper.update_passed() paper.end_time = datetime.datetime.now() + paper.update_status() paper.save() obt_marks = paper.marks_obtained tot_marks = paper.question_paper.total_marks |