summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrabhu Ramachandran2015-04-13 00:53:34 +0530
committerPrabhu Ramachandran2015-04-13 00:53:34 +0530
commit7f52ecfdbf27d3e2bf6f481c3f48a52f1a1a639a (patch)
treef6bbe837efd7a376fee0ee11befc84ee159eecc8
parent28415b148617057674d85aee9a2d3aaac36bf0d2 (diff)
parent1e26be51bc269fc3884d75ace33bfd6c4627547f (diff)
downloadonline_test-7f52ecfdbf27d3e2bf6f481c3f48a52f1a1a639a.tar.gz
online_test-7f52ecfdbf27d3e2bf6f481c3f48a52f1a1a639a.tar.bz2
online_test-7f52ecfdbf27d3e2bf6f481c3f48a52f1a1a639a.zip
Merge pull request #42 from prathamesh920/additional_features
Additional features
-rw-r--r--testapp/exam/forms.py16
-rw-r--r--testapp/exam/models.py47
-rw-r--r--testapp/exam/templates/exam/intro.html2
-rw-r--r--testapp/exam/templates/exam/question.html49
-rw-r--r--testapp/exam/templates/exam/quit.html4
-rw-r--r--testapp/exam/urls.py32
-rw-r--r--testapp/exam/views.py144
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>&nbsp;&nbsp;
+ {% elif question.type == "upload" %}
+ <br><button class="btn" type="submit" name="check" id="check" onClick="return validate();">Upload</button>&nbsp;&nbsp;
{% else %}
<button class="btn" type="submit" name="check" id="check" onClick="submitCode();">Check Answer</button>&nbsp;&nbsp;
{% 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>&nbsp;<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>&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/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