summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--testapp/exam/forms.py26
-rw-r--r--testapp/exam/models.py142
-rw-r--r--testapp/exam/tests.py278
-rw-r--r--testapp/exam/views.py67
-rw-r--r--testapp/static/exam/js/add_question.js29
-rw-r--r--testapp/static/exam/js/edit_question.js51
-rw-r--r--testapp/templates/exam/add_question.html6
-rw-r--r--testapp/templates/exam/add_quiz.html3
-rw-r--r--testapp/templates/exam/edit_question.html12
-rw-r--r--testapp/templates/exam/edit_quiz.html4
10 files changed, 480 insertions, 138 deletions
diff --git a/testapp/exam/forms.py b/testapp/exam/forms.py
index dc19783..7c66944 100644
--- a/testapp/exam/forms.py
+++ b/testapp/exam/forms.py
@@ -12,15 +12,21 @@ from taggit_autocomplete_modified import settings
from string import letters, punctuation, digits
import datetime
-QUESTION_TYPE_CHOICES = (
+LANGUAGES = (
+ ("select", "Select"),
("python", "Python"),
("bash", "Bash"),
- ("mcq", "MCQ"),
("C", "C Language"),
("C++", "C++ Language"),
("java", "Java Language"),
("scilab", "Scilab"),
- )
+ )
+
+QUESTION_TYPES = (
+ ("select", "Select"),
+ ("mcq", "Multiple Choice"),
+ ("code", "Code"),
+ )
UNAME_CHARS = letters + "._" + digits
PWD_CHARS = letters + punctuation + digits
@@ -51,8 +57,8 @@ class UserRegisterForm(forms.Form):
def clean_username(self):
u_name = self.cleaned_data["username"]
if u_name.strip(UNAME_CHARS):
- msg = "Only letters, digits, period and underscore characters are "\
- "allowed in username"
+ msg = "Only letters, digits, period and underscore characters are"\
+ " allowed in username"
raise forms.ValidationError(msg)
try:
User.objects.get(username__exact=u_name)
@@ -96,6 +102,7 @@ class UserRegisterForm(forms.Form):
return u_name, pwd
+
class UserLoginForm(forms.Form):
"""Creates a form which will allow the user to log into the system."""
@@ -115,6 +122,7 @@ class UserLoginForm(forms.Form):
raise forms.ValidationError("Invalid username/password")
return user
+
class QuizForm(forms.Form):
"""Creates a form to add or edit a Quiz.
It has the related fields and functions required."""
@@ -122,7 +130,6 @@ class QuizForm(forms.Form):
start_date = forms.DateField(initial=datetime.date.today)
duration = forms.IntegerField()
active = forms.BooleanField(required=False)
- tags = TagField(widget=TagAutocomplete())
description = forms.CharField(max_length=256, widget=forms.Textarea\
(attrs={'cols': 20, 'rows': 1}))
@@ -139,6 +146,7 @@ class QuizForm(forms.Form):
new_quiz.description = description
new_quiz.save()
+
class QuestionForm(forms.Form):
"""Creates a form to add or edit a Question.
It has the related fields and functions required."""
@@ -152,8 +160,10 @@ class QuestionForm(forms.Form):
(attrs={'cols': 40, 'rows': 1}))
options = forms.CharField(widget=forms.Textarea\
(attrs={'cols': 40, 'rows': 1}), required=False)
+ language = forms.CharField(max_length=20, widget=forms.Select\
+ (choices=LANGUAGES))
type = forms.CharField(max_length=8, widget=forms.Select\
- (choices=QUESTION_TYPE_CHOICES))
+ (choices=QUESTION_TYPES))
active = forms.BooleanField(required=False)
tags = TagField(widget=TagAutocomplete(), required=False)
snippet = forms.CharField(widget=forms.Textarea\
@@ -165,6 +175,7 @@ class QuestionForm(forms.Form):
points = self.cleaned_data['points']
test = self.cleaned_data["test"]
options = self.cleaned_data['options']
+ language = self.cleaned_data['language']
type = self.cleaned_data["type"]
active = self.cleaned_data["active"]
snippet = self.cleaned_data["snippet"]
@@ -175,6 +186,7 @@ class QuestionForm(forms.Form):
new_question.points = points
new_question.test = test
new_question.options = options
+ new_question.language = language
new_question.type = type
new_question.active = active
new_question.snippet = snippet
diff --git a/testapp/exam/models.py b/testapp/exam/models.py
index 758091f..42c5d5a 100644
--- a/testapp/exam/models.py
+++ b/testapp/exam/models.py
@@ -1,12 +1,12 @@
import datetime
+from random import sample, shuffle
from django.db import models
from django.contrib.auth.models import User
from taggit_autocomplete_modified.managers import TaggableManagerAutocomplete\
as TaggableManager
-from django.http import HttpResponse
-################################################################################
+###############################################################################
class Profile(models.Model):
"""Profile for a user to store roll number and other details."""
user = models.OneToOneField(User)
@@ -16,20 +16,25 @@ class Profile(models.Model):
position = models.CharField(max_length=64)
-QUESTION_TYPE_CHOICES = (
+LANGUAGES = (
("python", "Python"),
("bash", "Bash"),
- ("mcq", "MultipleChoice"),
("C", "C Language"),
("C++", "C++ Language"),
("java", "Java Language"),
("scilab", "Scilab"),
+ )
+
+
+QUESTION_TYPES = (
+ ("mcq", "Multiple Choice"),
+ ("code", "Code"),
)
-################################################################################
+###############################################################################
class Question(models.Model):
- """A question in the database."""
+ """Question for a quiz."""
# A one-line summary of the question.
summary = models.CharField(max_length=256)
@@ -43,31 +48,35 @@ class Question(models.Model):
# Test cases for the question in the form of code that is run.
test = models.TextField(blank=True)
- # Any multiple choice options. Place one option per line.
+ # Any multiple choice options. Place one option per line.
options = models.TextField(blank=True)
+ # The language for question.
+ language = models.CharField(max_length=24,
+ choices=LANGUAGES)
+
# The type of question.
- type = models.CharField(max_length=24, choices=QUESTION_TYPE_CHOICES)
+ type = models.CharField(max_length=24, choices=QUESTION_TYPES)
- # Is this question active or not. If it is inactive it will not be used
+ # Is this question active or not. If it is inactive it will not be used
# when creating a QuestionPaper.
active = models.BooleanField(default=True)
- #Code Snippet
+ # Snippet of code provided to the user.
snippet = models.CharField(max_length=256)
- #Tags for the Question.
+ # Tags for the Question.
tags = TaggableManager()
def __unicode__(self):
return self.summary
-################################################################################
+###############################################################################
class Answer(models.Model):
- """Answers submitted by users.
- """
- # The question for which we are an answer.
+ """Answers submitted by the users."""
+
+ # The question for which user answers.
question = models.ForeignKey(Question)
# The answer submitted by the user.
@@ -76,7 +85,7 @@ class Answer(models.Model):
# Error message when auto-checking the answer.
error = models.TextField()
- # Marks obtained for the answer. This can be changed by the teacher if the
+ # Marks obtained for the answer. This can be changed by the teacher if the
# grading is manual.
marks = models.FloatField(default=0.0)
@@ -87,44 +96,105 @@ class Answer(models.Model):
return self.answer
-################################################################################
+###############################################################################
class Quiz(models.Model):
"""A quiz that students will participate in. One can think of this
as the "examination" event.
"""
- # The starting/ending date of the quiz.
+ # The start date of the quiz.
start_date = models.DateField("Date of the quiz")
# This is always in minutes.
duration = models.IntegerField("Duration of quiz in minutes", default=20)
- # Is the quiz active. The admin should deactivate the quiz once it is
+ # Is the quiz active. The admin should deactivate the quiz once it is
# complete.
active = models.BooleanField(default=True)
# Description of quiz.
description = models.CharField(max_length=256)
- #Tags for the Quiz.
- tags = TaggableManager()
-
class Meta:
verbose_name_plural = "Quizzes"
def __unicode__(self):
desc = self.description or 'Quiz'
- return '%s: on %s for %d minutes' % (desc, self.start_date, self.duration)
+ return '%s: on %s for %d minutes' % (desc, self.start_date,
+ self.duration)
-################################################################################
+###############################################################################
class QuestionPaper(models.Model):
+ """Question paper stores the detail of the questions."""
+
+ # Question paper belongs to a particular quiz.
quiz = models.ForeignKey(Quiz)
- questions = models.ManyToManyField(Question)
+
+ # Questions that will be mandatory in the quiz.
+ fixed_questions = models.ManyToManyField(Question)
+
+ # Questions that will be fetched randomly from the Question Set.
+ random_questions = models.ManyToManyField("QuestionSet")
+
+ # Total marks for the question paper.
total_marks = models.FloatField()
+ def update_total_marks(self):
+ """ Returns the total marks for the Question Paper"""
+ marks = 0.0
+ questions = self.fixed_questions.all()
+ for question in questions:
+ marks += question.points
+ for question_set in self.random_questions.all():
+ marks += question_set.marks * question_set.num_questions
+ self.total_marks = marks
+ return None
+
+ def _get_questions_for_answerpaper(self):
+ """ Returns fixed and random questions for the answer paper"""
+ questions = []
+ questions = list(self.fixed_questions.all())
+ for question_set in self.random_questions.all():
+ questions += question_set.get_random_questions()
+ return questions
+
+ def make_answerpaper(self, user, ip):
+ """Creates an answer paper for the user to attempt the quiz"""
+ ans_paper = AnswerPaper(user=user, profile=user.profile, user_ip=ip)
+ ans_paper.start_time = datetime.datetime.now()
+ ans_paper.end_time = ans_paper.start_time \
+ + datetime.timedelta(minutes=self.quiz.duration)
+ ans_paper.question_paper = self
+ questions = self._get_questions_for_answerpaper()
+ question_ids = [str(x.id) for x in questions]
+ shuffle(questions)
+ ans_paper.questions = "|".join(question_ids)
+ ans_paper.save()
+ return ans_paper
+
+
+###############################################################################
+class QuestionSet(models.Model):
+ """Question set contains a set of questions from which random questions
+ will be selected for the quiz.
+ """
+
+ # Marks of each question of a particular Question Set
+ marks = models.FloatField()
+
+ # Number of questions to be fetched for the quiz.
+ num_questions = models.IntegerField()
+
+ # Set of questions for sampling randomly.
+ questions = models.ManyToManyField(Question)
+
+ def get_random_questions(self):
+ """ Returns random questions from set of questions"""
+ return sample(self.questions.all(), self.num_questions)
-################################################################################
+
+###############################################################################
class AnswerPaper(models.Model):
"""A answer paper for a student -- one per student typically.
"""
@@ -135,7 +205,8 @@ class AnswerPaper(models.Model):
# data.
profile = models.ForeignKey(Profile)
- # All questions that remains to attempt to perticular Student
+ # All questions that remain to be attempted for a particular Student
+ # (a list of ids separated by '|')
questions = models.CharField(max_length=128)
# The Quiz to which this question paper is attached to.
@@ -176,8 +247,10 @@ class AnswerPaper(models.Model):
return qs.count('|') + 1
def completed_question(self, question_id):
- """Removes the question from the list of questions and returns
-the next."""
+ """
+ Removes the completed question from the list of questions and
+ returns the next question.
+ """
qa = self.questions_answered
if len(qa) > 0:
self.questions_answered = '|'.join([qa, str(question_id)])
@@ -193,7 +266,9 @@ the next."""
return qs[0]
def skip(self):
- """Skip the current question and return the next available question."""
+ """
+ Skips the current question and returns the next available question.
+ """
qs = self.questions.split('|')
if len(qs) == 0:
return ''
@@ -223,13 +298,14 @@ the next."""
answered = ', '.join(sorted(qa))
return answered if answered else 'None'
- def get_total_marks(self):
+ def get_marks_obtained(self):
"""Returns the total marks earned by student for this paper."""
return sum([x.marks for x in self.answers.filter(marks__gt=0.0)])
def get_question_answers(self):
- """Return a dictionary with keys as questions and a list of the corresponding
- answers.
+ """
+ Return a dictionary with keys as questions and a list of the
+ corresponding answers.
"""
q_a = {}
for answer in self.answers.all():
diff --git a/testapp/exam/tests.py b/testapp/exam/tests.py
index 501deb7..b2ba36f 100644
--- a/testapp/exam/tests.py
+++ b/testapp/exam/tests.py
@@ -1,16 +1,270 @@
-"""
-This file demonstrates writing tests using the unittest module. These will pass
-when you run "manage.py test".
+from django.utils import unittest
+from exam.models import User, Profile, Question, Quiz, QuestionPaper,\
+ QuestionSet, AnswerPaper, Answer
+import datetime
-Replace this with more appropriate tests for your application.
-"""
-from django.test import TestCase
+def setUpModule():
+ # create user profile
+ user = User.objects.create_user(username='demo_user',
+ password='demo',
+ email='demo@test.com')
+ User.objects.create_user(username='demo_user2',
+ password='demo',
+ email='demo@test.com')
+ Profile.objects.create(user=user, roll_number=1, institute='IIT',
+ department='Chemical', position='Student')
+ # create 20 questions
+ for i in range(1, 21):
+ Question.objects.create(summary='Q%d' % (i), points=1)
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.assertEqual(1 + 1, 2)
+ # create a quiz
+ Quiz.objects.create(start_date='2014-06-16', duration=30, active=False,
+ description='demo quiz')
+
+
+def tearDownModule():
+ User.objects.all().delete()
+ Question.objects.all().delete()
+ Quiz.objects.all().delete()
+
+
+###############################################################################
+class ProfileTestCases(unittest.TestCase):
+ def setUp(self):
+ self.user = User.objects.get(pk=1)
+ self.profile = Profile.objects.get(pk=1)
+
+ def test_user_profile(self):
+ """ Test user profile"""
+ self.assertEqual(self.user.username, 'demo_user')
+ self.assertEqual(self.profile.user.username, 'demo_user')
+ self.assertEqual(int(self.profile.roll_number), 1)
+ self.assertEqual(self.profile.institute, 'IIT')
+ self.assertEqual(self.profile.department, 'Chemical')
+ self.assertEqual(self.profile.position, 'Student')
+
+
+###############################################################################
+class QuestionTestCases(unittest.TestCase):
+ def setUp(self):
+ # Single question details
+ self.question = Question(summary='Demo question', language='Python',
+ type='Code', active=True,
+ description='Write a function', points=1.0,
+ test='Test Cases', snippet='def myfunc()')
+ self.question.save()
+ self.question.tags.add('python', 'function')
+
+ def test_question(self):
+ """ Test question """
+ self.assertEqual(self.question.summary, 'Demo question')
+ self.assertEqual(self.question.language, 'Python')
+ self.assertEqual(self.question.type, 'Code')
+ self.assertFalse(self.question.options)
+ self.assertEqual(self.question.description, 'Write a function')
+ self.assertEqual(self.question.points, 1.0)
+ self.assertTrue(self.question.active)
+ self.assertEqual(self.question.test, 'Test Cases')
+ self.assertEqual(self.question.snippet, 'def myfunc()')
+ tag_list = []
+ for tag in self.question.tags.all():
+ tag_list.append(tag.name)
+ self.assertEqual(tag_list, ['python', 'function'])
+
+
+###############################################################################
+class QuizTestCases(unittest.TestCase):
+ def setUp(self):
+ self.quiz = Quiz.objects.get(pk=1)
+
+ def test_quiz(self):
+ """ Test Quiz"""
+ self.assertEqual((self.quiz.start_date).strftime('%Y-%m-%d'),
+ '2014-06-16')
+ self.assertEqual(self.quiz.duration, 30)
+ self.assertTrue(self.quiz.active is False)
+ self.assertEqual(self.quiz.description, 'demo quiz')
+
+
+###############################################################################
+class QuestionPaperTestCases(unittest.TestCase):
+ @classmethod
+ def setUpClass(self):
+ # All active questions
+ self.questions = Question.objects.filter(active=True)
+ self.quiz = Quiz.objects.get(id=1)
+
+ # create question paper
+ self.question_paper = QuestionPaper.objects.create(quiz=self.quiz,
+ total_marks=0.0)
+ # add fixed set of questions to the question paper
+ self.question_paper.fixed_questions.add(self.questions[3],
+ self.questions[5])
+ # create two QuestionSet for random questions
+ # QuestionSet 1
+ self.question_set_1 = QuestionSet.objects.create(marks=2,
+ num_questions=2)
+
+ # add pool of questions for random sampling
+ self.question_set_1.questions.add(self.questions[6], self.questions[7],
+ self.questions[8], self.questions[9])
+ # add question set 1 to random questions in Question Paper
+ self.question_paper.random_questions.add(self.question_set_1)
+
+ # QuestionSet 2
+ self.question_set_2 = QuestionSet.objects.create(marks=3,
+ num_questions=3)
+
+ # add pool of questions
+ self.question_set_2.questions.add(self.questions[11],
+ self.questions[12],
+ self.questions[13],
+ self.questions[14])
+ # add question set 2
+ self.question_paper.random_questions.add(self.question_set_2)
+
+ # ip address for AnswerPaper
+ self.ip = '127.0.0.1'
+
+ self.user = User.objects.get(pk=1)
+
+ def test_questionpaper(self):
+ """ Test question paper"""
+ self.assertEqual(self.question_paper.quiz.description, 'demo quiz')
+ self.assertEqual(list(self.question_paper.fixed_questions.all()),
+ [self.questions[3], self.questions[5]])
+
+ def test_update_total_marks(self):
+ """ Test update_total_marks() method of Question Paper"""
+ self.assertEqual(self.question_paper.total_marks, 0)
+ self.question_paper.update_total_marks()
+ self.assertEqual(self.question_paper.total_marks, 15)
+
+ def test_get_random_questions(self):
+ """ Test get_random_questions() method of Question Paper"""
+ random_questions_set_1 = self.question_set_1.get_random_questions()
+ random_questions_set_2 = self.question_set_2.get_random_questions()
+
+ # To check whether random questions are from random_question_set
+ questions_set_1 = set(self.question_set_1.questions.all())
+ random_set_1 = set(random_questions_set_1)
+ random_set_2 = set(random_questions_set_2)
+ boolean = questions_set_1.intersection(random_set_1) == random_set_1
+ self.assertTrue(boolean)
+ self.assertEqual(len(random_set_1), 2)
+ # To check that the questions are random.
+ # If incase not random then check that the order is diferent
+ try:
+ self.assertFalse(random_set_1 == random_set_2)
+ except AssertionError:
+ self.assertTrue(random_questions_set_1 != random_questions_set_2)
+
+ def test_get_questions_for_answerpaper(self):
+ """ Test get_questions_for_answerpaper() method of Question Paper"""
+ questions = self.question_paper._get_questions_for_answerpaper()
+ fixed = list(self.question_paper.fixed_questions.all())
+ question_set = self.question_paper.random_questions.all()
+ total_random_questions = 0
+ available_questions = []
+ for qs in question_set:
+ total_random_questions += qs.num_questions
+ available_questions += qs.questions.all()
+ self.assertEqual(total_random_questions, 5)
+ self.assertEqual(len(available_questions), 8)
+ self.assertEqual(len(questions), 7)
+
+ def test_make_answerpaper(self):
+ """ Test make_answerpaper() method of Question Paper"""
+ answerpaper = self.question_paper.make_answerpaper(self.user, self.ip)
+ self.assertIsInstance(answerpaper, AnswerPaper)
+ paper_questions = set((answerpaper.questions).split('|'))
+ self.assertEqual(len(paper_questions), 7)
+ fixed = {'4', '6'}
+ boolean = fixed.intersection(paper_questions) == fixed
+ self.assertTrue(boolean)
+
+
+###############################################################################
+class AnswerPaperTestCases(unittest.TestCase):
+ @classmethod
+ def setUpClass(self):
+ self.ip = '101.0.0.1'
+ self.user = User.objects.get(id=1)
+ self.profile = self.user.profile
+ self.quiz = Quiz.objects.get(pk=1)
+ self.question_paper = QuestionPaper(quiz=self.quiz, total_marks=3)
+ self.question_paper.save()
+
+ # create answerpaper
+ self.answerpaper = AnswerPaper(user=self.user, profile=self.profile,
+ questions='1|2|3',
+ question_paper=self.question_paper,
+ start_time='2014-06-13 12:20:19.791297',
+ end_time='2014-06-13 12:50:19.791297',
+ user_ip=self.ip)
+ self.answerpaper.questions_answered = '1'
+ self.answerpaper.save()
+
+ # answers for the Answer Paper
+ self.answer_right = Answer(question=Question.objects.get(id=1),
+ answer="Demo answer", correct=True, marks=1)
+ self.answer_wrong = Answer(question=Question.objects.get(id=2),
+ answer="My answer", correct=False, marks=0)
+ self.answer_right.save()
+ self.answer_wrong.save()
+ self.answerpaper.answers.add(self.answer_right)
+ self.answerpaper.answers.add(self.answer_wrong)
+
+ def test_answerpaper(self):
+ """ Test Answer Paper"""
+ self.assertEqual(self.answerpaper.user.username, 'demo_user')
+ self.assertEqual(self.answerpaper.profile_id, 1)
+ self.assertEqual(self.answerpaper.user_ip, self.ip)
+ questions = self.answerpaper.questions
+ num_questions = len(questions.split('|'))
+ self.assertEqual(questions, '1|2|3')
+ self.assertEqual(num_questions, 3)
+ self.assertEqual(self.answerpaper.question_paper, self.question_paper)
+ self.assertEqual(self.answerpaper.start_time,
+ '2014-06-13 12:20:19.791297')
+ self.assertEqual(self.answerpaper.end_time,
+ '2014-06-13 12:50:19.791297')
+
+ def test_current_question(self):
+ """ Test current_question() method of Answer Paper"""
+ current_question = self.answerpaper.current_question()
+ self.assertEqual(current_question, '2')
+
+ def test_completed_question(self):
+ """ Test completed_question() method of Answer Paper"""
+ question = self.answerpaper.completed_question(1)
+ self.assertEqual(self.answerpaper.questions_left(), 2)
+
+ def test_questions_left(self):
+ """ Test questions_left() method of Answer Paper"""
+ self.assertEqual(self.answerpaper.questions_left(), 2)
+
+ def test_skip(self):
+ """ Test skip() method of Answer Paper"""
+ next_question_id = self.answerpaper.skip()
+ self.assertTrue(next_question_id is not None)
+ self.assertEqual(next_question_id, '3')
+
+ def test_answered_str(self):
+ """ Test answered_str() method of Answer Paper"""
+ answered_question = self.answerpaper.get_answered_str()
+ self.assertEqual(answered_question, '1')
+
+ def test_get_marks_obtained(self):
+ """ Test get_marks_obtained() method of Answer Paper"""
+ self.assertEqual(self.answerpaper.get_marks_obtained(), 1.0)
+
+ def test_get_question_answer(self):
+ """ Test get_question_answer() method of Answer Paper"""
+ answered = self.answerpaper.get_question_answers()
+ first_answer = answered.values()[0][0]
+ self.assertEqual(first_answer.answer, 'Demo answer')
+ self.assertTrue(first_answer.correct)
+ self.assertEqual(len(answered), 2)
diff --git a/testapp/exam/views.py b/testapp/exam/views.py
index 92dd029..7353d82 100644
--- a/testapp/exam/views.py
+++ b/testapp/exam/views.py
@@ -127,7 +127,8 @@ def user_register(request):
context_instance=ci)
else:
form = UserRegisterForm()
- return my_render_to_response('exam/register.html', {'form': form})
+ return my_render_to_response('exam/register.html', {'form': form},
+ context_instance=ci)
def quizlist_user(request):
@@ -166,7 +167,7 @@ def results_user(request):
papers = AnswerPaper.objects.filter(user=user)
quiz_marks = []
for paper in papers:
- marks_obtained = paper.get_total_marks()
+ marks_obtained = paper.get_marks_obtained()
max_marks = paper.question_paper.total_marks
percentage = round((marks_obtained/max_marks)*100, 2)
temp = paper.question_paper.quiz.description, marks_obtained,\
@@ -187,7 +188,6 @@ def edit_quiz(request):
duration = request.POST.getlist('duration')
active = request.POST.getlist('active')
description = request.POST.getlist('description')
- tags = request.POST.getlist('tags')
for j, quiz_id in enumerate(quiz_list):
quiz = Quiz.objects.get(id=quiz_id)
@@ -196,14 +196,6 @@ def edit_quiz(request):
quiz.active = active[j]
quiz.description = description[j]
quiz.save()
- edit_tags = tags[j]
- quiz.save()
- for tag in quiz.tags.all():
- quiz.tags.remove(tag)
- tags_split = edit_tags.split(', ')
- for i in range(0, len(tags_split)-1):
- tag = tags_split[i].strip()
- quiz.tags.add(tag)
return my_redirect("/exam/manage/showquiz/")
@@ -222,7 +214,6 @@ def edit_question(request):
type = request.POST.getlist('type')
active = request.POST.getlist('active')
snippet = request.POST.getlist('snippet')
- tags = request.POST.getlist('tags')
for j, question_id in enumerate(question_list):
question = Question.objects.get(id=question_id)
question.summary = summary[j]
@@ -233,14 +224,7 @@ def edit_question(request):
question.active = active[j]
question.snippet = snippet[j]
question.type = type[j]
- edit_tags = tags[j]
question.save()
- for tag in question.tags.all():
- question.tags.remove(tag)
- tags_split = edit_tags.split(',')
- for i in range(0, len(tags_split)-1):
- tag = tags_split[i].strip()
- question.tags.add(tag)
return my_redirect("/exam/manage/questions")
@@ -331,10 +315,6 @@ def add_quiz(request, quiz_id=None):
if quiz_id is None:
form.save()
quiz = Quiz.objects.order_by("-id")[0]
- tags = form['tags'].data.split(',')
- for tag in tags:
- tag = tag.strip()
- quiz.tags.add(tag)
return my_redirect("/exam/manage/designquestionpaper")
else:
d = Quiz.objects.get(id=quiz_id)
@@ -344,12 +324,6 @@ def add_quiz(request, quiz_id=None):
d.description = form['description'].data
d.save()
quiz = Quiz.objects.get(id=quiz_id)
- for tag in quiz.tags.all():
- quiz.tags.remove(tag)
- tags = form['tags'].data.split(',')
- for i in range(0, len(tags)-1):
- tag = tags[i].strip()
- quiz.tags.add(tag)
return my_redirect("/exam/manage/showquiz")
else:
return my_render_to_response('exam/add_quiz.html',
@@ -368,14 +342,6 @@ def add_quiz(request, quiz_id=None):
form.initial['duration'] = d.duration
form.initial['description'] = d.description
form.initial['active'] = d.active
- form_tags = d.tags.all()
- form_tags_split = form_tags.values('name')
- initial_tags = ""
- for tag in form_tags_split:
- initial_tags = initial_tags + str(tag['name']).strip() + ","
- if (initial_tags == ","):
- initial_tags = ""
- form.initial['tags'] = initial_tags
return my_render_to_response('exam/add_quiz.html',
{'form': form},
context_instance=ci)
@@ -398,7 +364,7 @@ def show_all_questionpapers(request, questionpaper_id=None):
if request.method == "POST" and request.POST.get('add') == "add":
return my_redirect("/exam/manage/designquestionpaper/" +
- questionpaper_id)
+ questionpaper_id)
if request.method == "POST" and request.POST.get('delete') == "delete":
data = request.POST.getlist('papers')
@@ -545,7 +511,7 @@ def manual_questionpaper(request, questionpaper_id=None):
msg = 'No matching Question found...'
tags = Tag.objects.all()
context = {'data': {'questions': fetched_questions,
- 'tags': tags, 'msg': msg}}
+ 'tags': tags, 'msg': msg}}
return my_render_to_response('exam/manual_questionpaper.html',
context,
context_instance=ci)
@@ -578,7 +544,7 @@ def manual_questionpaper(request, questionpaper_id=None):
msg = 'No matching Question found...'
tags = Tag.objects.all()
context = {'data': {'questions': fetched_questions,
- 'tags': tags, 'msg': msg}}
+ 'tags': tags, 'msg': msg}}
return my_render_to_response('exam/manual_questionpaper.html',
context,
context_instance=ci)
@@ -658,18 +624,9 @@ def start(request, questionpaper_id=None):
msg = 'You do not have a profile and cannot take the quiz!'
raise Http404(msg)
- new_paper = AnswerPaper(user=user, user_ip=ip,
- question_paper=questionpaper, profile=profile)
- new_paper.start_time = datetime.datetime.now()
- new_paper.end_time = datetime.datetime.now()
+ new_paper = questionpaper.make_answerpaper(user, ip,)
# Make user directory.
user_dir = get_user_dir(user)
-
- questions = [str(_.id) for _ in questionpaper.questions.all()]
- random.shuffle(questions)
-
- new_paper.questions = "|".join(questions)
- new_paper.save()
return start(request, questionpaper_id)
@@ -822,7 +779,7 @@ def complete(request, reason=None, questionpaper_id=None):
else:
q_paper = QuestionPaper.objects.get(id=questionpaper_id)
paper = AnswerPaper.objects.get(user=user, question_paper=q_paper)
- obt_marks = paper.get_total_marks()
+ obt_marks = paper.get_marks_obtained()
tot_marks = paper.question_paper.total_marks
if obt_marks == paper.question_paper.total_marks:
context = {'message': "Hurray ! You did an excellent job.\
@@ -953,14 +910,6 @@ def show_all_quiz(request):
form.initial['duration'] = d.duration
form.initial['active'] = d.active
form.initial['description'] = d.description
- form_tags = d.tags.all()
- form_tags_split = form_tags.values('name')
- initial_tags = ""
- for tag in form_tags_split:
- initial_tags = initial_tags + str(tag['name']).strip() + ","
- if (initial_tags == ","):
- initial_tags = ""
- form.initial['tags'] = initial_tags
forms.append(form)
return my_render_to_response('exam/edit_quiz.html',
{'forms': forms, 'data': data},
diff --git a/testapp/static/exam/js/add_question.js b/testapp/static/exam/js/add_question.js
index ba17492..56fdd1f 100644
--- a/testapp/static/exam/js/add_question.js
+++ b/testapp/static/exam/js/add_question.js
@@ -135,7 +135,19 @@ function textareaformat()
$('#id_snippet').bind('blur', function( event ){
document.getElementById("id_snippet").rows=1;
document.getElementById("id_snippet").cols=40;
- });
+ });
+
+
+ $('#id_type').bind('focus', function(event){
+ var type = document.getElementById('id_type');
+ type.style.border = '1px solid #ccc';
+ });
+
+ $('#id_language').bind('focus', function(event){
+ var language = document.getElementById('id_language');
+ language.style.border = '1px solid #ccc';
+ });
+
$('#id_type').bind('change',function(event){
var value = document.getElementById('id_type').value;
if(value == 'mcq')
@@ -167,7 +179,20 @@ function textareaformat()
function autosubmit()
{
- if (document.getElementById('id_type').value == 'mcq')
+ var language = document.getElementById('id_language');
+ if(language.value == 'select')
+ {
+ language.style.border="solid red";
+ return false;
+ }
+ var type = document.getElementById('id_type');
+ if(type.value == 'select')
+ {
+ type.style.border = 'solid red';
+ return false;
+ }
+
+ if (type.value == 'mcq')
{
var value = document.getElementById('id_options').value;
if(value.split('\n').length < 4)
diff --git a/testapp/static/exam/js/edit_question.js b/testapp/static/exam/js/edit_question.js
index 28d95f9..c5df631 100644
--- a/testapp/static/exam/js/edit_question.js
+++ b/testapp/static/exam/js/edit_question.js
@@ -120,6 +120,7 @@ function textareaformat()
var option = document.getElementsByName('options');
var descriptions = document.getElementsByName('description');
var snippets = document.getElementsByName('snippet');
+ var language = document.getElementsByName('language')
var type = document.getElementsByName('type');
var tags = document.getElementsByName('tags');
for (var i=0;i<point.length;i++)
@@ -130,16 +131,18 @@ function textareaformat()
snippets[i].id=snippets[i].id + i;
option[i].id=option[i].id + i;
type[i].id = type[i].id + i;
+ language[i].id = language[i].id + i;
tags[i].id = tags[i].id + i;
}
for(var i=0;i<point.length;i++)
{
var point_id = document.getElementById('id_points'+i);
point_id.setAttribute('class','mini-text');
- var tags_id = document.getElementById('id_tags'+i);
+ var tags_id = document.getElementById('id_tags'+i);
tags_id.setAttribute('class','ac_input');
- tags_id.setAttribute('autocomplete','off');
- var type_id = document.getElementById('id_type'+i);
+ tags_id.setAttribute('autocomplete','off');
+ var language_id = document.getElementById('id_language'+i);
+ var type_id = document.getElementById('id_type'+i);
type_id.setAttribute('class','select-type');
type_id.onchange = showOptions;
var value = type_id.value;
@@ -150,12 +153,21 @@ function textareaformat()
test_id.onfocus = gainfocus;
test_id.onblur = lostfocus;
var snippet_id = document.getElementById('id_snippet'+i);
- $(snippet_id).bind('focus',function(event){
+ $(snippet_id).bind('focus', function(event){
+ console.log("dv")
this.rows = 5;
});
$(snippet_id).bind('keydown', function (event){
catchTab(snippet_id,event);
});
+
+ $(language_id).bind('focus', function(event){
+ this.style.border = '1px solid #ccc';
+ });
+ $(type_id).bind('focus', function(event){
+ this.style.border = '1px solid #ccc';
+ });
+
var option_id = document.getElementById('id_options' + i);
option_id.onfocus = gainfocus;
option_id.onblur = lostfocus;
@@ -163,13 +175,12 @@ function textareaformat()
{
document.getElementById('id_options'+i).style.visibility='hidden';
document.getElementById('label_option'+(i+1)).innerHTML = "";
-
}
document.getElementById('my'+ (i+1)).innerHTML = desc_id.value;
- jQuery().ready(function()
- {
- jQuery("#id_tags" + i).autocomplete("/taggit_autocomplete_modified/json", { multiple: true });
- });
+ jQuery().ready(function(){
+ jQuery("#id_tags" + i).autocomplete("/taggit_autocomplete_modified/json", { multiple: true });
+ });
+
}
}
@@ -199,6 +210,7 @@ function showOptions(e)
{
document.getElementById('id_options'+no).style.visibility = 'visible';
document.getElementById('label_option'+ (no+1)).innerHTML = "Options : "
+ document.getElementById('label_option'+ (no+1)).style.fontWeight = 'bold';
}
else
{
@@ -217,14 +229,33 @@ function lostfocus(e)
this.rows = 1;
}
+function changeColor(element)
+{
+ element.style.border = 'solid red';
+}
function autosubmit()
{
var total_form = document.getElementsByName('summary').length;
var empty_options = 0 ;
var count_mcq = 0;
-
+ var language;
+ var type;
+
for (var i=0;i<total_form;i++)
{
+ language = document.getElementById('id_language'+i);
+ type = document.getElementById('id_type'+i);
+ if(language.value == 'select')
+ {
+ changeColor(language);
+ return false;
+ }
+ if(type.value == 'select')
+ {
+ changeColor(type);
+ return false;
+ }
+
if (document.getElementById('id_type' + i).value != 'mcq')
{
continue;
diff --git a/testapp/templates/exam/add_question.html b/testapp/templates/exam/add_question.html
index b49d7de..b0b22b1 100644
--- a/testapp/templates/exam/add_question.html
+++ b/testapp/templates/exam/add_question.html
@@ -22,8 +22,10 @@
{% csrf_token %}
<center><table class=span1>
<tr><td>Summary: <td>{{ form.summary }}{{ form.summary.errors }}
- <tr><td>Points:<td><button class="btn-mini" type="button" onClick="increase(frm);">+</button>{{ form.points }}<button class="btn-mini" type="button" onClick="decrease(frm);">-</button>{{ form.points.errors }} &nbsp; Active: &nbsp; {{ form.active }}{{form.active.errors}} &nbsp; Type: &nbsp;{{ form.type }}{{form.type.errors}}
- <tr><td><strong>Rendered: </strong><td><p id='my'></p>
+ <tr><td> Language: <td> {{form.language}}{{form.language.errors}}
+ <tr><td> Active: <td> {{ form.active }}{{form.active.errors}} &nbsp; Type: &nbsp;{{ form.type }}{{form.type.errors}}
+ <tr><td>Points:<td><button class="btn-mini" type="button" onClick="increase(frm);">+</button>{{ form.points }}<button class="btn-mini" type="button" onClick="decrease(frm);">-</button>{{ form.points.errors }}
+ <tr><td><strong>Rendered: </strong><td><p id='my'></p>
<tr><td>Description: <td>{{ form.description}} {{form.description.errors}}
<tr><td>Test: <td>{{ form.test }}{{form.test.errors}}
<tr><td>Snippet: <td>{{ form.snippet }}{{ form.snippet.errors }}</td></tD></td></tr>
diff --git a/testapp/templates/exam/add_quiz.html b/testapp/templates/exam/add_quiz.html
index 9851584..c2533de 100644
--- a/testapp/templates/exam/add_quiz.html
+++ b/testapp/templates/exam/add_quiz.html
@@ -5,11 +5,8 @@
{% block css %}
<link rel="stylesheet" href="{{ URL_ROOT }}/static/exam/css/question_quiz.css" type="text/css" />
-<link rel="stylesheet" media="all" type="text/css" href="{{ URL_ROOT }}/static/exam/css/autotaggit.css" />
{% 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/add_quiz.js"></script>
{% endblock %}
{% block onload %} onload="javascript:test();" {% endblock %}
diff --git a/testapp/templates/exam/edit_question.html b/testapp/templates/exam/edit_question.html
index 73e61d7..b28cc3e 100644
--- a/testapp/templates/exam/edit_question.html
+++ b/testapp/templates/exam/edit_question.html
@@ -30,15 +30,15 @@
<center><table class=span1>
<tr><td><b>Summary:</b> <td>{{ form.summary }}{{ form.summary.errors }}
-
- <tr><td><b>Points:<td><button class="btn-mini" name={{forloop.counter}} type="button" onClick="increase(frm,{{forloop.counter}});">+</button>{{ form.points }}<button class="btn-mini" type="button" onClick="decrease(frm,{{forloop.counter}});">-</button>{{ form.points.errors }} &nbsp; Active: &nbsp; {{ form.active }}{{form.active.errors}} &nbsp; Type: &nbsp;{{ form.type }}{{form.type.errors}}
-
+ <tr><td><b> Language: </b><td> {{form.language}}{{form.language.errors}}
+ <tr><td><b> Active: </b><td>&nbsp; {{ form.active }}{{form.active.errors}} &nbsp; Type: &nbsp;{{ form.type }}{{form.type.errors}}
+ <tr><td><b>Points:<td><button class="btn-mini" name={{forloop.counter}} type="button" onClick="increase(frm,{{forloop.counter}});">+</button>{{ form.points }}<button class="btn-mini" type="button" onClick="decrease(frm,{{forloop.counter}});">-</button>{{ form.points.errors }}
<tr><td><strong>Rendered: </strong><td><p id='my{{forloop.counter}}'></p>
<tr><td><b>Description: <td>{{ form.description }} {{form.description.errors}}
- <tr><td><b>Test: <td>{{ form.test }}{{form.test.errors}}
+ <tr><td><b>Test: <td>{{ form.test }}{{form.test.errors}}
<tr><td><b>Snippet: <td>{{ form.snippet }}{{ form.snippet.errors }}</td></b></td></tr>
- <tr><td>Tags: <td>{{ form.tags }}
- <tr><td id='label_option{{forloop.counter}}'><b>Options: <td>{{ form.options }} {{form.options.errors}} {{form.options.helptext}}
+ <tr><td><b>Tags: </b><td>{{ form.tags }}
+ <tr><td id='label_option{{forloop.counter}}'><b>Options:<td>{{ form.options }} {{form.options.errors}} {{form.options.helptext}}
</table></center>
</div>
</div>
diff --git a/testapp/templates/exam/edit_quiz.html b/testapp/templates/exam/edit_quiz.html
index 0ea4aae..cf80df1 100644
--- a/testapp/templates/exam/edit_quiz.html
+++ b/testapp/templates/exam/edit_quiz.html
@@ -5,13 +5,10 @@
{% block css %}
<link rel="stylesheet" href="{{ URL_ROOT }}/static/exam/css/question_quiz.css" type="text/css" />
-<link rel="stylesheet" media="all" type="text/css" href="{{ URL_ROOT }}/static/exam/css/autotaggit.css" />
{% endblock %}
{% block script %}
<script src="{{ URL_ROOT }}/static/exam/js/edit_quiz.js"></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>
{% endblock %}
{% block onload %} onload = 'javascript:form_load();' {% endblock %}
@@ -25,7 +22,6 @@
<tr><td><b>Start Date: <td>{{ form.start_date}}
<tr><td><b>Duration: <td> {{ form.duration }}
<tr><td><b>Active: <td> {{ form.active }}
- <tr><td><b>Tags: <td> {{ form.tags }}
<tr><td><b>Description: <td> {{ form.description }}
<hr>
{% endfor %}