diff options
-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 %} |