diff options
Diffstat (limited to 'testapp')
-rw-r--r-- | testapp/exam/forms.py | 26 | ||||
-rw-r--r-- | testapp/exam/models.py | 142 | ||||
-rw-r--r-- | testapp/exam/tests.py | 278 | ||||
-rw-r--r-- | testapp/exam/views.py | 67 | ||||
-rw-r--r-- | testapp/static/exam/js/add_question.js | 29 | ||||
-rw-r--r-- | testapp/static/exam/js/edit_question.js | 51 | ||||
-rw-r--r-- | testapp/templates/exam/add_question.html | 6 | ||||
-rw-r--r-- | testapp/templates/exam/add_quiz.html | 3 | ||||
-rw-r--r-- | testapp/templates/exam/edit_question.html | 12 | ||||
-rw-r--r-- | testapp/templates/exam/edit_quiz.html | 4 |
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 }} Active: {{ form.active }}{{form.active.errors}} Type: {{ 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}} Type: {{ 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 }} Active: {{ form.active }}{{form.active.errors}} Type: {{ form.type }}{{form.type.errors}} - + <tr><td><b> Language: </b><td> {{form.language}}{{form.language.errors}} + <tr><td><b> Active: </b><td> {{ form.active }}{{form.active.errors}} Type: {{ 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 %} |