diff options
author | prathamesh | 2014-06-16 17:04:40 +0530 |
---|---|---|
committer | prathamesh | 2014-06-16 17:04:40 +0530 |
commit | 763f96559bd1827ce87a72708d72efc9361ef588 (patch) | |
tree | b3de9316a59d31c785251c58baecab6c7a068c11 /testapp | |
parent | 5adb38569bec47ea0a1ea63e22ceec8906717b04 (diff) | |
download | online_test-763f96559bd1827ce87a72708d72efc9361ef588.tar.gz online_test-763f96559bd1827ce87a72708d72efc9361ef588.tar.bz2 online_test-763f96559bd1827ce87a72708d72efc9361ef588.zip |
Models modified.
QuestionPaper model modified for generating random questions.
Added language field to Question model.
Removed tags from Quiz model.
Template and javascript for Add and Edit questions modified.
Added test cases for models.
Diffstat (limited to 'testapp')
-rw-r--r-- | testapp/exam/forms.py | 23 | ||||
-rw-r--r-- | testapp/exam/models.py | 140 | ||||
-rw-r--r-- | testapp/exam/tests.py | 222 | ||||
-rw-r--r-- | testapp/exam/views.py | 56 | ||||
-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, 420 insertions, 126 deletions
diff --git a/testapp/exam/forms.py b/testapp/exam/forms.py index dc19783..e82ce3a 100644 --- a/testapp/exam/forms.py +++ b/testapp/exam/forms.py @@ -12,7 +12,8 @@ from taggit_autocomplete_modified import settings from string import letters, punctuation, digits import datetime -QUESTION_TYPE_CHOICES = ( +QUESTION_LANGUAGE_CHOICES = ( + ("select", "Select"), ("python", "Python"), ("bash", "Bash"), ("mcq", "MCQ"), @@ -20,7 +21,13 @@ QUESTION_TYPE_CHOICES = ( ("C++", "C++ Language"), ("java", "Java Language"), ("scilab", "Scilab"), - ) + ) + +QUESTION_TYPE_CHOICES = ( + ("select", "Select"), + ("mcq", "Multiple Choice"), + ("code", "Code"), + ) UNAME_CHARS = letters + "._" + digits PWD_CHARS = letters + punctuation + digits @@ -51,8 +58,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 +103,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 +123,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 +131,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 +147,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,6 +161,8 @@ 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=QUESTION_LANGUAGE_CHOICES)) type = forms.CharField(max_length=8, widget=forms.Select\ (choices=QUESTION_TYPE_CHOICES)) active = forms.BooleanField(required=False) @@ -165,6 +176,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 +187,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..ca53b2c 100644 --- a/testapp/exam/models.py +++ b/testapp/exam/models.py @@ -1,12 +1,12 @@ import datetime +from random import sample 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,25 +16,30 @@ class Profile(models.Model): position = models.CharField(max_length=64) -QUESTION_TYPE_CHOICES = ( +QUESTION_LANGUAGE_CHOICES = ( ("python", "Python"), ("bash", "Bash"), - ("mcq", "MultipleChoice"), ("C", "C Language"), ("C++", "C++ Language"), ("java", "Java Language"), ("scilab", "Scilab"), + ) + + +QUESTION_TYPE_CHOICES = ( + ("mcq", "Multiple Choice"), + ("code", "Code"), ) -################################################################################ +############################################################################### class Question(models.Model): - """A question in the database.""" + """A question details in the database.""" # A one-line summary of the question. summary = models.CharField(max_length=256) - # The question text, should be valid HTML. + # The question text, should be a valid HTML. description = models.TextField() # Number of points for the question. @@ -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=QUESTION_LANGUAGE_CHOICES) + # The type of question. type = models.CharField(max_length=24, choices=QUESTION_TYPE_CHOICES) - # 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 + # Code Snippet 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,103 @@ 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 get_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 + return marks + + 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, profile, ip): + """Creates an answer paper for the user to attempt the quiz""" + ans_paper = AnswerPaper(user=user, profile=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(_.id) for _ in questions] + ans_paper.questions = "|".join(question_ids) + ans_paper.save() + return ans_paper + + +############################################################################### +class QuestionSet(models.Model): + """Question set contains 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 +203,8 @@ class AnswerPaper(models.Model): # data. profile = models.ForeignKey(Profile) - # All questions that remains to attempt to perticular Student + # All questions that are left to attempt 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 +245,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 +264,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 +296,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..ac63301 100644 --- a/testapp/exam/tests.py +++ b/testapp/exam/tests.py @@ -1,16 +1,214 @@ -""" -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 -Replace this with more appropriate tests for your application. -""" -from django.test import TestCase +class ModelsTestCase(unittest.TestCase): + @classmethod + def setUpClass(self): + """ Initial fixtures for testing environment""" -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.assertEqual(1 + 1, 2) + # create user profile + self.user = User.objects.create_user(username='demo_user', + password='demo', + email='demo@test.com') + self.profile = Profile.objects.create(user=self.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)) + + # All active questions + self.questions = Question.objects.filter(active=True) + + # Single question details + self.question = self.questions[0] + self.question.summary = 'Demo question' + self.question.language = 'Python' + self.question.type = 'Code' + self.question.options = None + self.question.description = 'Write a function' + self.question.points = 1.0 + self.question.active = True + self.question.test = 'Test Cases' + self.question.snippet = 'def myfunc()' + self.question.tags.add('python', 'function') + + # create a quiz + self.quiz = Quiz.objects.create(start_date='2014-06-16', + duration=30, active=False, + description='demo quiz') + + # create question paper + self.quest_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=0.0) + + # add fixed set of questions to the question paper + self.quest_paper.fixed_questions.add(self.questions[3], + self.questions[5]) + + # create two QuestionSet for random questions + # QuestionSet 1 + self.quest_set_1 = QuestionSet.objects.create(marks=2, num_questions=2) + + # add pool of questions for random sampling + self.quest_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.quest_paper.random_questions.add(self.quest_set_1) + + # QuestionSet 2 + self.quest_set_2 = QuestionSet.objects.create(marks=3, num_questions=3) + + # add pool of questions + self.quest_set_2.questions.add(self.questions[11], self.questions[12], + self.questions[13], self.questions[14]) + + # add question set 2 + self.quest_paper.random_questions.add(self.quest_set_2) + + # ip address for AnswerPaper + self.ip = '127.0.0.1' + + # create answerpaper + self.answerpaper = AnswerPaper(user=self.user, profile=self.profile, + questions='1|2|3', + question_paper=self.quest_paper, + start_time='2014-06-13 12:20:19.791297', + end_time='2014-06-13 12:50:19.791297', + user_ip=self.ip) + +############################################################################### + def test_user_profile(self): + """ Test user profile""" + self.assertIs(type(self.profile), type(Profile())) + self.assertEqual(self.user.username, 'demo_user') + self.assertEqual(self.profile.user.username, 'demo_user') + self.assertEqual(self.profile.roll_number, 1) + self.assertEqual(self.profile.institute, 'IIT') + self.assertEqual(self.profile.department, 'Chemical') + self.assertEqual(self.profile.position, 'Student') + + def test_question(self): + """ Test question """ + self.assertIs(type(self.question), type(Question())) + self.assertEqual(self.question.summary, 'Demo question') + self.assertEqual(self.question.language, 'Python') + self.assertEqual(self.question.type, 'Code') + self.assertTrue(self.question.options is None) + 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']) + self.assertEqual(len(self.questions), 20) + + def test_quiz(self): + """ Test Quiz""" + self.assertIs(type(self.quiz), type(Quiz())) + self.assertEqual(self.quiz.start_date, '2014-06-16') + self.assertEqual(self.quiz.duration, 30) + self.assertTrue(self.quiz.active is False) + self.assertEqual(self.quiz.description, 'demo quiz') + + def test_questionpaper(self): + """ Test question paper""" + self.assertIs(type(self.quest_paper), type(QuestionPaper())) + self.assertEqual(self.quest_paper.quiz.description, 'demo quiz') + self.assertEqual(list(self.quest_paper.fixed_questions.all()), + [self.questions[3], self.questions[5]]) + + def test_get_random_questions(self): + """ Test get_random_questions() method of Question Paper """ + random_questions_set_1 = set(self.quest_set_1.get_random_questions()) + random_questions_set_2 = set(self.quest_set_2.get_random_questions()) + + # To check whether random questions are from random_question_set + boolean = set(self.quest_set_1.questions.all()).\ + intersection(random_questions_set_1)\ + == random_questions_set_1 + self.assertTrue(boolean) + self.assertEqual(len(random_questions_set_1), 2) + self.assertFalse(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.quest_paper._get_questions_for_answerpaper() + fixed = list(self.quest_paper.fixed_questions.all()) + quest_set = self.quest_paper.random_questions.all() + total_random_questions = 0 + available_questions = [] + for qs in quest_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.quest_paper.make_answerpaper(self.user, + self.profile, self.ip) + self.assertIs(type(answerpaper), type(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) + + def test_answerpaper(self): + """ Test Answer Paper""" + self.assertIs(type(self.answerpaper), type(AnswerPaper())) + 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.quest_paper) + self.assertEqual(self.answerpaper.question_paper, self.quest_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.assertTrue(current_question is not None) + + def test_completed_question(self): + """ Test completed_question() method of Answer Paper""" + question = self.answerpaper.completed_question(3) + self.assertTrue(question is not None) + 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""" + self.assertTrue(self.answerpaper.skip() is not None) + + def test_answered_str(self): + """ Test answered_str() method of Answer Paper""" + self.assertEqual(self.answerpaper.get_answered_str(), 'None') + + def test_get_marks_obtained(self): + """ Test get_marks_obtained() method of Answer Paper""" + self.assertEqual(self.answerpaper.get_marks_obtained(), 0) + + def test_get_question_answer(self): + """ Test get_question_answer() method of Answer Paper""" + self.assertEqual(self.answerpaper.get_question_answers(), {}) diff --git a/testapp/exam/views.py b/testapp/exam/views.py index 92dd029..76773cb 100644 --- a/testapp/exam/views.py +++ b/testapp/exam/views.py @@ -166,7 +166,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 +187,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 +195,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 +213,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 +223,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 +314,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 +323,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 +341,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 +363,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 +510,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 +543,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) @@ -665,7 +630,8 @@ def start(request, questionpaper_id=None): # Make user directory. user_dir = get_user_dir(user) - questions = [str(_.id) for _ in questionpaper.questions.all()] + questions = [str(_.id) for _ in\ + questionpaper._get_questions_for_answerpaper()] random.shuffle(questions) new_paper.questions = "|".join(questions) @@ -822,7 +788,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 +919,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 %} |