diff options
Diffstat (limited to 'testapp/exam')
-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 | 32 | ||||
-rw-r--r-- | testapp/exam/views.py | 144 |
7 files changed, 205 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..ebf1018 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_num): """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_num) 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..592937a 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_num }}/{{ 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..f49b62f 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_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/{{ 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/urls.py b/testapp/exam/urls.py index f8a6cb8..8a01a81 100644 --- a/testapp/exam/urls.py +++ b/testapp/exam/urls.py @@ -1,20 +1,22 @@ -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_num>\d+)/(?P<questionpaper_id>\d+)/$', 'start'), + url(r'^quit/(?P<attempt_num>\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_num>\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_num>\d+)/(?P<questionpaper_id>\d+)/$',\ + 'check'), url(r'^intro/$', 'start'), url(r'^manage/$', 'prof_manage'), @@ -25,22 +27,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..89b2fd7 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_num': 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_num': 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_num=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_num, questionpaper_id) try: old_paper = AnswerPaper.objects.get( - question_paper=questionpaper, user=user) + question_paper=questionpaper, user=user, attempt_number=attempt_num) q = old_paper.current_question() - return show_question(request, q, questionpaper_id) + return show_question(request, q, attempt_num, 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_num) # Make user directory. user_dir = get_user_dir(user) - return start(request, questionpaper_id) + return start(request, attempt_num, questionpaper_id) -def question(request, q_id, questionpaper_id, success_msg=None): +def question(request, q_id, attempt_num, 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_num, 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_num, 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_num, questionpaper_id) else: - return question(request, q_id, questionpaper_id, success_msg) + return question(request, q_id, attempt_num, questionpaper_id, success_msg) -def check(request, q_id, questionpaper_id=None): +def check(request, q_id, attempt_num=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_num, + 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,23 @@ 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_num, 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 + # if time-up at upload question then the form is submitted without + # validation + if 'assignment' in request.FILES: + 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 +784,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_num, 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_num, questionpaper_id) context = {'question': question, 'error_message': err_msg, 'paper': paper, 'last_attempt': user_code, 'quiz_name': paper.question_paper.quiz.description, @@ -785,10 +814,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_num, questionpaper_id) else: next_q = paper.completed_question(question.id) - return show_question(request, next_q, + return show_question(request, next_q, attempt_num, questionpaper_id, success_msg) @@ -824,14 +853,15 @@ def validate_answer(user, user_answer, question): return correct, success, message -def quit(request, questionpaper_id=None): +def quit(request, attempt_num=None, questionpaper_id=None): """Show the quit page when the user logs out.""" - context = {'id': questionpaper_id} + context = {'id': questionpaper_id, + 'attempt_num': attempt_num} 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_num=None, questionpaper_id=None): """Show a page to inform user that the quiz has been compeleted.""" user = request.user @@ -842,11 +872,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_num) 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 |