diff options
author | Prabhu Ramachandran | 2013-04-27 15:28:28 +0530 |
---|---|---|
committer | Prabhu Ramachandran | 2013-04-27 15:28:28 +0530 |
commit | 8b6ac259503323bc3d8333382d3769e5d10f162a (patch) | |
tree | 5d260a3db043492ef731b4241cf0f07563591743 /testapp/exam | |
parent | fd044e4a9f08366c9425cb241b7452da2ba904e1 (diff) | |
parent | 5c7f66806e4be50985655b7c12bf3190ee91ae46 (diff) | |
download | online_test-8b6ac259503323bc3d8333382d3769e5d10f162a.tar.gz online_test-8b6ac259503323bc3d8333382d3769e5d10f162a.tar.bz2 online_test-8b6ac259503323bc3d8333382d3769e5d10f162a.zip |
Merge branch 'model_changes' of ...
https://github.com/hardythe1/online_test into master.
Conflicts:
production.cfg
testapp/production.py
Diffstat (limited to 'testapp/exam')
-rw-r--r-- | testapp/exam/forms.py | 130 | ||||
-rw-r--r-- | testapp/exam/migrations/0001_initial.py | 193 | ||||
-rw-r--r-- | testapp/exam/migrations/__init__.py | 0 | ||||
-rw-r--r-- | testapp/exam/models.py | 41 | ||||
-rw-r--r-- | testapp/exam/urls.py | 44 | ||||
-rw-r--r-- | testapp/exam/views.py | 802 |
6 files changed, 892 insertions, 318 deletions
diff --git a/testapp/exam/forms.py b/testapp/exam/forms.py index a5ca26f..7bbf601 100644 --- a/testapp/exam/forms.py +++ b/testapp/exam/forms.py @@ -1,44 +1,57 @@ from django import forms -from exam.models import Profile +from exam.models import Profile,Quiz,Question from django.contrib.auth import authenticate from django.contrib.auth.models import User +from taggit.managers import TaggableManager +from taggit.forms import TagField +from taggit_autocomplete_modified.managers import TaggableManagerAutocomplete +from taggit_autocomplete_modified.widgets import TagAutocomplete +from taggit_autocomplete_modified import settings from string import letters, punctuation, digits +import datetime + +QUESTION_TYPE_CHOICES = ( + ("python", "Python"), + ("bash", "Bash"), + ("mcq", "MCQ"), + ) UNAME_CHARS = letters + "._" + digits PWD_CHARS = letters + punctuation + digits class UserRegisterForm(forms.Form): + """A Class to create new form for User's Registration. + It has the various fields and functions required to register + a new user to the system""" - username = forms.CharField(max_length=30, - help_text='Letters, digits, period and underscores only.') + username = forms.CharField\ + (max_length=30, help_text='Letters, digits,\ + period and underscores only.') email = forms.EmailField() - password = forms.CharField(max_length=30, - widget=forms.PasswordInput()) - confirm_password = forms.CharField(max_length=30, - widget=forms.PasswordInput()) + password = forms.CharField(max_length=30, widget=forms.PasswordInput()) + confirm_password = forms.CharField\ + (max_length=30, widget=forms.PasswordInput()) first_name = forms.CharField(max_length=30) last_name = forms.CharField(max_length=30) - roll_number = forms.CharField(max_length=30, - help_text="Use a dummy if you don't have one.") - institute = forms.CharField(max_length=128, - help_text='Institute/Organization') - department = forms.CharField(max_length=64, - help_text='Department you work/study at') - position = forms.CharField(max_length=64, - help_text='Student/Faculty/Researcher/Industry/etc.') + roll_number = forms.CharField\ + (max_length=30, help_text="Use a dummy if you don't have one.") + institute = forms.CharField\ + (max_length=128, help_text='Institute/Organization') + department = forms.CharField\ + (max_length=64, help_text='Department you work/study at') + position = forms.CharField\ + (max_length=64, help_text='Student/Faculty/Researcher/Industry/etc.') 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" raise forms.ValidationError(msg) - try: - User.objects.get(username__exact = u_name) + User.objects.get(username__exact=u_name) raise forms.ValidationError("Username already exists.") except User.DoesNotExist: return u_name @@ -46,8 +59,8 @@ class UserRegisterForm(forms.Form): def clean_password(self): pwd = self.cleaned_data['password'] if pwd.strip(PWD_CHARS): - raise forms.ValidationError("Only letters, digits and punctuation are \ - allowed in password") + raise forms.ValidationError("Only letters, digits and punctuation\ + are allowed in password") return pwd def clean_confirm_password(self): @@ -80,16 +93,83 @@ class UserRegisterForm(forms.Form): return u_name, pwd class UserLoginForm(forms.Form): - username = forms.CharField(max_length = 30) + """Creates a form which will allow the user to log into the system.""" + + username = forms.CharField(max_length=30) password = forms.CharField(max_length=30, widget=forms.PasswordInput()) def clean(self): super(UserLoginForm, self).clean() - u_name, pwd = self.cleaned_data["username"], self.cleaned_data["password"] - user = authenticate(username = u_name, password = pwd) - + try: + u_name, pwd = self.cleaned_data["username"],\ + self.cleaned_data["password"] + user = authenticate(username=u_name, password=pwd) + except Exception: + raise forms.ValidationError\ + ("Username and/or Password is not entered") if not user: 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.""" + + 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})) + + def save(self): + start_date = self.cleaned_data["start_date"] + duration = self.cleaned_data["duration"] + active = self.cleaned_data['active'] + description = self.cleaned_data["description"] + + new_quiz = Quiz() + new_quiz.start_date = start_date + new_quiz.duration = duration + new_quiz.active = active + 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.""" + + summary = forms.CharField(widget=forms.Textarea\ + (attrs={'cols': 40, 'rows': 1})) + description = forms.CharField(widget=forms.Textarea\ + (attrs={'cols': 40, 'rows': 1})) + points = forms.FloatField() + test = forms.CharField(widget=forms.Textarea\ + (attrs={'cols': 40, 'rows': 1})) + options = forms.CharField(widget=forms.Textarea\ + (attrs={'cols': 40, 'rows': 1}),required=False) + type = forms.CharField(max_length=8, widget=forms.Select\ + (choices=QUESTION_TYPE_CHOICES)) + active = forms.BooleanField(required=False) + tags = TagField(widget=TagAutocomplete(),required=False) + snippet = forms.CharField(widget=forms.Textarea\ + (attrs={'cols': 40, 'rows': 1}),required=False) + + def save(self): + summary = self.cleaned_data["summary"] + description = self.cleaned_data["description"] + points = self.cleaned_data['points'] + test = self.cleaned_data["test"] + options = self.cleaned_data['options'] + type = self.cleaned_data["type"] + active = self.cleaned_data["active"] + + new_question = Question() + new_question.summary = summary + new_question.description = description + new_question.points = points + new_question.test = test + new_question.options = options + new_question.type = type + new_question.active = active + new_question.save() diff --git a/testapp/exam/migrations/0001_initial.py b/testapp/exam/migrations/0001_initial.py deleted file mode 100644 index 49048cc..0000000 --- a/testapp/exam/migrations/0001_initial.py +++ /dev/null @@ -1,193 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding model 'Profile' - db.create_table('exam_profile', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.User'], unique=True)), - ('roll_number', self.gf('django.db.models.fields.CharField')(max_length=20)), - ('institute', self.gf('django.db.models.fields.CharField')(max_length=128)), - ('department', self.gf('django.db.models.fields.CharField')(max_length=64)), - ('position', self.gf('django.db.models.fields.CharField')(max_length=64)), - )) - db.send_create_signal('exam', ['Profile']) - - # Adding model 'Question' - db.create_table('exam_question', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('summary', self.gf('django.db.models.fields.CharField')(max_length=256)), - ('description', self.gf('django.db.models.fields.TextField')()), - ('points', self.gf('django.db.models.fields.FloatField')(default=1.0)), - ('test', self.gf('django.db.models.fields.TextField')(blank=True)), - ('options', self.gf('django.db.models.fields.TextField')(blank=True)), - ('type', self.gf('django.db.models.fields.CharField')(max_length=24)), - ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), - )) - db.send_create_signal('exam', ['Question']) - - # Adding model 'Answer' - db.create_table('exam_answer', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('question', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['exam.Question'])), - ('answer', self.gf('django.db.models.fields.TextField')()), - ('error', self.gf('django.db.models.fields.TextField')()), - ('marks', self.gf('django.db.models.fields.FloatField')(default=0.0)), - ('correct', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('exam', ['Answer']) - - # Adding model 'Quiz' - db.create_table('exam_quiz', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('start_date', self.gf('django.db.models.fields.DateField')()), - ('duration', self.gf('django.db.models.fields.IntegerField')(default=20)), - ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('description', self.gf('django.db.models.fields.CharField')(max_length=256)), - )) - db.send_create_signal('exam', ['Quiz']) - - # Adding model 'QuestionPaper' - db.create_table('exam_questionpaper', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), - ('profile', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['exam.Profile'])), - ('quiz', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['exam.Quiz'])), - ('start_time', self.gf('django.db.models.fields.DateTimeField')()), - ('user_ip', self.gf('django.db.models.fields.CharField')(max_length=15)), - ('key', self.gf('django.db.models.fields.CharField')(max_length=10)), - ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), - ('questions', self.gf('django.db.models.fields.CharField')(max_length=128)), - ('questions_answered', self.gf('django.db.models.fields.CharField')(max_length=128)), - ('comments', self.gf('django.db.models.fields.TextField')()), - )) - db.send_create_signal('exam', ['QuestionPaper']) - - # Adding M2M table for field answers on 'QuestionPaper' - db.create_table('exam_questionpaper_answers', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('questionpaper', models.ForeignKey(orm['exam.questionpaper'], null=False)), - ('answer', models.ForeignKey(orm['exam.answer'], null=False)) - )) - db.create_unique('exam_questionpaper_answers', ['questionpaper_id', 'answer_id']) - - - def backwards(self, orm): - - # Deleting model 'Profile' - db.delete_table('exam_profile') - - # Deleting model 'Question' - db.delete_table('exam_question') - - # Deleting model 'Answer' - db.delete_table('exam_answer') - - # Deleting model 'Quiz' - db.delete_table('exam_quiz') - - # Deleting model 'QuestionPaper' - db.delete_table('exam_questionpaper') - - # Removing M2M table for field answers on 'QuestionPaper' - db.delete_table('exam_questionpaper_answers') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'exam.answer': { - 'Meta': {'object_name': 'Answer'}, - 'answer': ('django.db.models.fields.TextField', [], {}), - 'correct': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'error': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'marks': ('django.db.models.fields.FloatField', [], {'default': '0.0'}), - 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['exam.Question']"}) - }, - 'exam.profile': { - 'Meta': {'object_name': 'Profile'}, - 'department': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'institute': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'position': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'roll_number': ('django.db.models.fields.CharField', [], {'max_length': '20'}), - 'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}) - }, - 'exam.question': { - 'Meta': {'object_name': 'Question'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'options': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'points': ('django.db.models.fields.FloatField', [], {'default': '1.0'}), - 'summary': ('django.db.models.fields.CharField', [], {'max_length': '256'}), - 'test': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'type': ('django.db.models.fields.CharField', [], {'max_length': '24'}) - }, - 'exam.questionpaper': { - 'Meta': {'object_name': 'QuestionPaper'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'answers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['exam.Answer']", 'symmetrical': 'False'}), - 'comments': ('django.db.models.fields.TextField', [], {}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'key': ('django.db.models.fields.CharField', [], {'max_length': '10'}), - 'profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['exam.Profile']"}), - 'questions': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'questions_answered': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'quiz': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['exam.Quiz']"}), - 'start_time': ('django.db.models.fields.DateTimeField', [], {}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), - 'user_ip': ('django.db.models.fields.CharField', [], {'max_length': '15'}) - }, - 'exam.quiz': { - 'Meta': {'object_name': 'Quiz'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'description': ('django.db.models.fields.CharField', [], {'max_length': '256'}), - 'duration': ('django.db.models.fields.IntegerField', [], {'default': '20'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'start_date': ('django.db.models.fields.DateField', [], {}) - } - } - - complete_apps = ['exam'] diff --git a/testapp/exam/migrations/__init__.py b/testapp/exam/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/testapp/exam/migrations/__init__.py +++ /dev/null diff --git a/testapp/exam/models.py b/testapp/exam/models.py index 717e02e..00d32e4 100644 --- a/testapp/exam/models.py +++ b/testapp/exam/models.py @@ -1,7 +1,9 @@ import datetime 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.""" @@ -43,6 +45,12 @@ class Question(models.Model): # 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 = models.CharField(max_length=256) + + #Tags for the Question. + tags = TaggableManager() def __unicode__(self): return self.summary @@ -89,6 +97,10 @@ class Quiz(models.Model): # Description of quiz. description = models.CharField(max_length=256) + + #Tags for the Quiz. + tags = TaggableManager() + class Meta: verbose_name_plural = "Quizzes" @@ -97,9 +109,13 @@ class Quiz(models.Model): desc = self.description or 'Quiz' return '%s: on %s for %d minutes'%(desc, self.start_date, self.duration) - ################################################################################ class QuestionPaper(models.Model): + quiz = models.ForeignKey(Quiz) + questions = models.ManyToManyField(Question) + +################################################################################ +class AnswerPaper(models.Model): """A question paper for a student -- one per student typically. """ # The user taking this question paper. @@ -108,23 +124,22 @@ class QuestionPaper(models.Model): # The user's profile, we store a reference to make it easier to access the # data. profile = models.ForeignKey(Profile) - + + # All questions that remains to attempt to perticular Student + questions = models.CharField(max_length=128) + # The Quiz to which this question paper is attached to. - quiz = models.ForeignKey(Quiz) + question_paper = models.ForeignKey(QuestionPaper) # The time when this paper was started by the user. start_time = models.DateTimeField() + + # The time when this paper was ended by the user. + end_time = models.DateTimeField() # User's IP which is logged. user_ip = models.CharField(max_length=15) - # Unused currently. - key = models.CharField(max_length=10) - # used to allow/stop a user from retaking the question paper. - active = models.BooleanField(default = True) - - # The questions (a list of ids separated by '|') - questions = models.CharField(max_length=128) # The questions successfully answered (a list of ids separated by '|') questions_answered = models.CharField(max_length=128) @@ -152,7 +167,7 @@ class QuestionPaper(models.Model): def completed_question(self, question_id): """Removes the question from the list of questions and returns - the next.""" +the next.""" qa = self.questions_answered if len(qa) > 0: self.questions_answered = '|'.join([qa, str(question_id)]) @@ -188,7 +203,7 @@ class QuestionPaper(models.Model): except AttributeError: # total_seconds is new in Python 2.7. :( secs = dt.seconds + dt.days*24*3600 - total = self.quiz.duration*60.0 + total = self.question_paper.quiz.duration*60.0 remain = max(total - secs, 0) return int(remain) diff --git a/testapp/exam/urls.py b/testapp/exam/urls.py index 34e329f..b3cfceb 100644 --- a/testapp/exam/urls.py +++ b/testapp/exam/urls.py @@ -3,14 +3,44 @@ from django.conf.urls.defaults import patterns, include, url urlpatterns = patterns('exam.views', url(r'^$', 'index'), url(r'^login/$', 'user_login'), - url(r'^register/$', 'user_register'), + url(r'^quizzes/$','quizlist_user'), + url(r'^results/$','results_user'), url(r'^start/$', 'start'), - url(r'^quit/$', 'quit'), - url(r'^complete/$', 'complete'), - url(r'^monitor/$', 'monitor'), - url(r'^monitor/(?P<quiz_id>\d+)/$', 'monitor'), - url(r'^user_data/(?P<username>[a-zA-Z0-9_.]+)/$', 'user_data'), - url(r'^grade_user/(?P<username>[a-zA-Z0-9_.]+)/$', 'grade_user'), + url(r'^start/(?P<questionpaper_id>\d+)/$','start'), + url(r'^quit/(?P<answerpaper_id>\d+)/$', 'quit'), + url(r'^intro/$','start'), + url(r'^complete/$', 'complete'), + url(r'^complete/(?P<answerpaper_id>\d+)/$', 'complete'), + url(r'^register/$', 'user_register'), url(r'^(?P<q_id>\d+)/$', 'question'), url(r'^(?P<q_id>\d+)/check/$', 'check'), + url(r'^(?P<q_id>\d+)/check/(?P<questionpaper_id>\d+)/$', 'check'), + + + url(r'^manage/$', 'prof_manage'), + url(r'^manage/addquestion/$', 'add_question'), + url(r'^manage/addquestion/(?P<question_id>\d+)/$', 'add_question'), + url(r'^manage/addquiz/$', 'add_quiz'), + url(r'^manage/editquiz/$', 'edit_quiz'), + url(r'^manage/editquestion/$', 'edit_question'), + url(r'^manage/addquiz/(?P<quiz_id>\d+)/$', 'add_quiz'), + url(r'^manage/gradeuser/$', 'show_all_users'), + url(r'^manage/gradeuser/(?P<username>[a-zA-Z0-9_.]+)/$', 'grade_user'), + url(r'^manage/questions/$', 'show_all_questions'), + url(r'^manage/showquiz/$','show_all_quiz'), + url(r'^manage/monitor/$', 'monitor'), + url(r'^manage/showquestionpapers/$','show_all_questionpapers'), + url(r'^manage/showquestionpapers/(?P<questionpaper_id>\d+)/$',\ + 'show_all_questionpapers'), + url(r'^manage/monitor/(?P<quiz_id>\d+)/$', 'monitor'), + url(r'^manage/user_data/(?P<username>[a-zA-Z0-9_.]+)/$','user_data'), + url(r'^manage/designquestionpaper/$','design_questionpaper'), + url(r'^manage/designquestionpaper/(?P<questionpaper_id>\d+)/$',\ + 'design_questionpaper'), + url(r'^manage/designquestionpaper/automatic/(?P<questionpaper_id>\d+)/$',\ + 'automatic_questionpaper'), + url(r'^manage/designquestionpaper/automatic$','automatic_questionpaper'), + url(r'^manage/designquestionpaper/manual$','manual_questionpaper'), + url(r'^manage/designquestionpaper/manual/(?P<questionpaper_id>\d+)/$',\ + 'manual_questionpaper'), ) diff --git a/testapp/exam/views.py b/testapp/exam/views.py index c178a0b..5a5f5fe 100644 --- a/testapp/exam/views.py +++ b/testapp/exam/views.py @@ -5,15 +5,18 @@ import stat from os.path import dirname, pardir, abspath, join, exists import datetime +from django.http import HttpResponse from django.contrib.auth import login, logout, authenticate from django.shortcuts import render_to_response, get_object_or_404, redirect from django.template import RequestContext from django.http import Http404 from django.db.models import Sum - +from taggit.models import Tag +from itertools import chain # Local imports. -from exam.models import Quiz, Question, QuestionPaper, Profile, Answer, User -from exam.forms import UserRegisterForm, UserLoginForm +from exam.models import Quiz, Question, QuestionPaper +from exam.models import Profile, Answer, AnswerPaper, User +from exam.forms import UserRegisterForm, UserLoginForm, QuizForm, QuestionForm from exam.xmlrpc_clients import code_server from settings import URL_ROOT @@ -22,10 +25,11 @@ OUTPUT_DIR = abspath(join(dirname(__file__), pardir, 'output')) def my_redirect(url): - """An overridden redirect to deal with URL_ROOT-ing. See settings.py - for details.""" + """An overridden redirect to deal with URL_ROOT-ing. See settings.py +for details.""" return redirect(URL_ROOT + url) + def my_render_to_response(template, context=None, **kwargs): """Overridden render_to_response. """ @@ -33,34 +37,74 @@ def my_render_to_response(template, context=None, **kwargs): context = {'URL_ROOT': URL_ROOT} else: context['URL_ROOT'] = URL_ROOT - return render_to_response(template, context, **kwargs) + return render_to_response(template, context, **kwargs) def gen_key(no_of_chars): """Generate a random key of the number of characters.""" allowed_chars = string.digits+string.uppercase return ''.join([random.choice(allowed_chars) for i in range(no_of_chars)]) - + + def get_user_dir(user): """Return the output directory for the user.""" + user_dir = join(OUTPUT_DIR, str(user.username)) if not exists(user_dir): os.mkdir(user_dir) - # Make it rwx by others. - os.chmod(user_dir, stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH \ - | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR \ + # Make it rwx by others. + os.chmod(user_dir, stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH\ + | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR\ | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP) return user_dir - + + +def is_moderator(user): + """Check if the user is having moderator rights""" + if user.groups.filter(name='moderator').count() == 1: + return True + + +def fetch_questions(request): + """Fetch questions from database based on the given search conditions & + tags""" + set1 = set() + set2 = set() + first_tag = request.POST.get('first_tag') + first_condition = request.POST.get('first_condition') + second_tag = request.POST.get('second_tag') + second_condition = request.POST.get('second_condition') + third_tag = request.POST.get('third_tag') + question1 = set(Question.objects.filter(tags__name__in=[first_tag])) + question2 = set(Question.objects.filter(tags__name__in=[second_tag])) + question3 = set(Question.objects.filter(tags__name__in=[third_tag])) + if first_condition == 'and': + set1 = question1.intersection(question2) + if second_condition == 'and': + set2 = set1.intersection(question3) + else: + set2 = set1.union(question3) + else: + set1 = question1.union(question2) + if second_condition == 'and': + set2 = set1.intersection(question3) + else: + set2 = set1.union(question3) + return set2 + + def index(request): """The start page. """ user = request.user if user.is_authenticated(): + if user.groups.filter(name='moderator').count() > 0: + return my_redirect('/exam/manage/') return my_redirect("/exam/start/") return my_redirect("/exam/login/") + def user_register(request): """ Register a new user. Create a user and corresponding profile and store roll_number also.""" @@ -74,34 +118,465 @@ def user_register(request): if form.is_valid(): data = form.cleaned_data u_name, pwd = form.save() - - new_user = authenticate(username = u_name, password = pwd) + new_user = authenticate(username=u_name, password=pwd) login(request, new_user) return my_redirect("/exam/start/") - else: return my_render_to_response('exam/register.html', - {'form':form}, + {'form': form}, context_instance=RequestContext(request)) else: form = UserRegisterForm() return my_render_to_response('exam/register.html', - {'form':form}, + {'form': form}, context_instance=RequestContext(request)) + + +def quizlist_user(request): + """Show All Quizzes that is available to logged-in user.""" + user = request.user + avail_quiz = list(QuestionPaper.objects.filter(quiz__active=True)) + user_answerpapers = AnswerPaper.objects.filter(user=user) + user_quiz = [] + + if user_answerpapers.count() == 0: + context = {'quizzes': avail_quiz} + return my_render_to_response("exam/quizzes_user.html", context) + + for paper in user_answerpapers: + for quiz in avail_quiz: + if paper.question_paper.id == quiz.id and \ + paper.end_time != paper.start_time: + avail_quiz.remove(quiz) + + context = {'quizzes': avail_quiz, 'user': user} + return my_render_to_response("exam/quizzes_user.html", context) + + +def results_user(request): + """Show list of Results of Quizzes that is taken by logged-in user.""" + user = request.user + papers = AnswerPaper.objects.filter(user=user) + quiz_marks = [] + for paper in papers: + temp = paper.question_paper.quiz.description, paper.get_total_marks() + quiz_marks.append(temp) + context = {'papers': quiz_marks} + return my_render_to_response("exam/results_user.html", context) + + +def edit_quiz(request): + """Edit the list of quizzes seleted by the user for editing.""" + + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + quiz_list = request.POST.getlist('quizzes') + start_date = request.POST.getlist('start_date') + 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) + quiz.start_date = start_date[j] + quiz.duration = duration[j] + 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/") + + +def edit_question(request): + """Edit the list of questions seleted by the user for editing.""" + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + + question_list = request.POST.getlist('questions') + summary = request.POST.getlist('summary') + description = request.POST.getlist('description') + points = request.POST.getlist('points') + test = request.POST.getlist('test') + options = request.POST.getlist('options') + 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] + question.description = description[j] + question.points = points[j] + question.test = test[j] + question.options = options[j] + question.type = type[j] + edit_tags = tags[j] + question.active = active[j] + question.snippet = snippet[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") + + +def add_question(request, question_id=None): + """To add a new question in the database. + Create a new question and store it.""" + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + if request.method == "POST": + form = QuestionForm(request.POST) + if form.is_valid(): + data = form.cleaned_data + if question_id is None: + form.save() + question = Question.objects.order_by("-id")[0] + tags = form['tags'].data.split(',') + for i in range(0, len(tags)-1): + tag = tags[i].strip() + question.tags.add(tag) + return my_redirect("/exam/manage/questions") + else: + d = Question.objects.get(id=question_id) + d.summary = form['summary'].data + d.description = form['description'].data + d.points = form['points'].data + d.test = form['test'].data + d.options = form['options'].data + d.type = form['type'].data + d.active = form['active'].data + d.snippet = form['snippet'].data + d.save() + question = Question.objects.get(id=question_id) + for tag in question.tags.all(): + question.tags.remove(tag) + tags = form['tags'].data.split(', ') + for i in range(0, len(tags)-1): + tag = tags[i].strip() + question.tags.add(tag) + return my_redirect("/exam/manage/questions") + else: + return my_render_to_response('exam/add_question.html', + {'form': form}, context_instance=RequestContext(request)) + else: + if question_id is None: + form = QuestionForm() + return my_render_to_response('exam/add_question.html', + {'form': form}, context_instance=RequestContext(request)) + else: + d = Question.objects.get(id=question_id) + form = QuestionForm() + form.initial['summary'] = d.summary + form.initial['description'] = d.description + form.initial['points'] = d.points + form.initial['test'] = d.test + form.initial['options'] = d.options + form.initial['type'] = d.type + form.initial['active'] = d.active + form.initial['snippet'] = d.snippet + 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_question.html', + {'form': form}, + context_instance=RequestContext(request)) + + +def add_quiz(request, quiz_id=None): + """To add a new quiz in the database. + Create a new question and store it.""" + + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + if request.method == "POST": + form = QuizForm(request.POST) + if form.is_valid(): + data = form.cleaned_data + 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) + d.start_date = form['start_date'].data + d.duration = form['duration'].data + d.active = form['active'].data + 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', + {'form': form}, + context_instance=RequestContext(request)) + else: + if quiz_id is None: + form = QuizForm() + return my_render_to_response('exam/add_quiz.html', + {'form': form}, context_instance=RequestContext(request)) + else: + d = Quiz.objects.get(id=quiz_id) + form = QuizForm() + form.initial['start_date'] = d.start_date + 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=RequestContext(request)) + + +def design_questionpaper(request, questionpaper_id=None): + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + return my_render_to_response('exam/add_questionpaper.html', {}, + context_instance=RequestContext(request)) + + +def show_all_questionpapers(request, questionpaper_id=None): + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + + if request.method == "POST" and request.POST.get('add') == "add": + return my_redirect("/exam/manage/designquestionpaper/" + \ + questionpaper_id) + + if request.method == "POST" and request.POST.get('delete') == "delete": + data = request.POST.getlist('papers') + q_paper = QuestionPaper.objects.get(id=questionpaper_id) + for i in data: + q_paper.questions.remove(Question.objects.get(id=i)) + question_paper = QuestionPaper.objects.all() + context = {'papers': question_paper} + return my_render_to_response('exam/showquestionpapers.html', context, + context_instance=RequestContext(request)) + if questionpaper_id is None: + qu_papers = QuestionPaper.objects.all() + context = {'papers': qu_papers} + return my_render_to_response('exam/showquestionpapers.html', context, + context_instance=RequestContext(request)) + else: + qu_papers = QuestionPaper.objects.get(id=questionpaper_id) + quiz = qu_papers.quiz + questions = qu_papers.questions.all() + context = {'papers': {'quiz': quiz, 'questions': questions}} + return my_render_to_response('exam/editquestionpaper.html', context, + context_instance=RequestContext(request)) + + +def automatic_questionpaper(request, questionpaper_id=None): + """Generate automatic question paper for a particular quiz""" + + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + + if questionpaper_id is None: + if request.method == "POST": + if request.POST.get('save') == 'save': + quiz = Quiz.objects.order_by("-id")[0] + quest_paper = QuestionPaper() + quest_paper.quiz = quiz + quest_paper.save() + questions = request.POST.getlist('questions') + for i in questions: + if i.isdigit(): + q = Question.objects.get(id=i) + quest_paper.questions.add(q) + return my_redirect('/exam/manage/showquiz') + else: + no_questions = int(request.POST.get('questions')) + fetched_questions = fetch_questions(request) + n = len(fetched_questions) + msg = '' + if (no_questions < n): + i = n - no_questions + for i in range(0, i): + fetched_questions.pop() + elif (no_questions > n): + msg = 'The given Criteria does not satisfy the number\ + of Questions...' + tags = Tag.objects.all() + context = {'data': {'questions': fetched_questions, + 'tags': tags, + 'msg': msg}} + return my_render_to_response(\ + 'exam/automatic_questionpaper.html', context, + context_instance=RequestContext(request)) + else: + tags = Tag.objects.all() + context = {'data': {'tags': tags}} + return my_render_to_response('exam/automatic_questionpaper.html', + context, context_instance=RequestContext(request)) + + else: + if request.method == "POST": + if request.POST.get('save') == 'save': + quest_paper = QuestionPaper.objects.get(id=questionpaper_id) + questions = request.POST.getlist('questions') + for i in questions: + if i.isdigit(): + q = Question.objects.get(id=i) + quest_paper.questions.add(q) + return my_redirect('/exam/manage/showquiz') + else: + no_questions = int(request.POST.get('questions')) + fetched_questions = fetch_questions(request) + n = len(fetched_questions) + msg = '' + if(no_questions < n): + i = n - no_questions + for i in range(0, i): + fetched_questions.pop() + elif(no_questions > n): + msg = 'The given Criteria does not satisfy the number of \ + Questions...' + tags = Tag.objects.all() + context = {'data': {'questions': fetched_questions, + 'tags': tags, + 'msg': msg}} + return my_render_to_response\( + 'exam/automatic_questionpaper.html', context, + context_instance=RequestContext(request)) + else: + tags = Tag.objects.all() + context = {'data': {'tags': tags}} + return my_render_to_response('exam/automatic_questionpaper.html', + context, context_instance=RequestContext(request)) + + +def manual_questionpaper(request, questionpaper_id=None): + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page!') + + if questionpaper_id is None: + if request.method == "POST": + if request.POST.get('save') == 'save': + questions = request.POST.getlist('questions') + quiz = Quiz.objects.order_by("-id")[0] + quest_paper = QuestionPaper() + quest_paper.quiz = quiz + quest_paper.save() + for i in questions: + q = Question.objects.get(id=i) + quest_paper.questions.add(q) + return my_redirect('/exam/manage/showquiz') + else: + fetched_questions = fetch_questions(request) + n = len(fetched_questions) + msg = '' + if (n == 0): + msg = 'No matching Question found...' + tags = Tag.objects.all() + context = {'data': {'questions': fetched_questions,\ + 'tags': tags, 'msg': msg}} + return my_render_to_response('exam/manual_questionpaper.html', + context, + context_instance=RequestContext(request)) + else: + tags = Tag.objects.all() + context = {'data': {'tags': tags}} + return my_render_to_response('exam/manual_questionpaper.html', + context, context_instance=RequestContext(request)) + + else: + if request.method == "POST": + if request.POST.get('save') == 'save': + quest_paper = QuestionPaper.objects.get(id=questionpaper_id) + questions = request.POST.getlist('questions') + for i in questions: + q = Question.objects.get(id=i) + quest_paper.questions.add(q) + return my_redirect('/exam/manage/showquiz') + else: + fetched_questions = fetch_questions(request) + n = len(fetched_questions) + msg = '' + if (n == 0): + msg = 'No matching Question found...' + tags = Tag.objects.all() + context = {'data': {'questions': fetched_questions,\ + 'tags': tags, 'msg': msg}} + return my_render_to_response('exam/manual_questionpaper.html', + context, + context_instance=RequestContext(request)) + else: + tags = Tag.objects.all() + context = {'data': {'tags': tags}} + return my_render_to_response('exam/manual_questionpaper.html', + context, context_instance=RequestContext(request)) + + +def prof_manage(request): + """Take credentials of the user with professor/moderator + rights/permissions and log in.""" + user = request.user + if user.is_authenticated()\ + and user.groups.filter(name='moderator').count() > 0: + context = {'user': user} + return my_render_to_response('manage.html', context) + return my_redirect('/exam/login/') + def user_login(request): """Take the credentials of the user and log the user in.""" user = request.user if user.is_authenticated(): - return my_redirect("/exam/start/") + if user.groups.filter(name='moderator').count() > 0: + return my_redirect('/exam/manage/') + return my_redirect("/exam/intro/") if request.method == "POST": form = UserLoginForm(request.POST) if form.is_valid(): user = form.cleaned_data login(request, user) - return my_redirect("/exam/start/") + if user.groups.filter(name='moderator').count() > 0: + return my_redirect('/exam/manage/') + return my_redirect('/exam/login/') else: context = {"form": form} return my_render_to_response('exam/login.html', context, @@ -112,21 +587,28 @@ def user_login(request): return my_render_to_response('exam/login.html', context, context_instance=RequestContext(request)) -def start(request): + +def start(request, questionpaper_id=None): + """Check the user cedentials and if any quiz is available, + start the exam.""" user = request.user + if questionpaper_id is None: + return my_redirect('/exam/quizzes/') try: - # Right now the app is designed so there is only one active quiz - # at a particular time. - quiz = Quiz.objects.get(active=True) - except Quiz.DoesNotExist: - msg = 'No active quiz found, please contact your '\ - 'instructor/administrator. Please login again thereafter.' + """Right now the app is designed so there is only one active quiz + at a particular time.""" + questionpaper = QuestionPaper.objects.get(id=questionpaper_id) + except QuestionPaper.DoesNotExist: + msg = 'Quiz not found, please contact your '\ + 'instructor/administrator. Please login again thereafter.' return complete(request, reason=msg) + try: - old_paper = QuestionPaper.objects.get(user=user, quiz=quiz) + old_paper = AnswerPaper.objects.get(\ + question_paper=questionpaper, user=user) q = old_paper.current_question() - return show_question(request, q) - except QuestionPaper.DoesNotExist: + return show_question(request, q, questionpaper_id) + except AnswerPaper.DoesNotExist: ip = request.META['REMOTE_ADDR'] key = gen_key(10) try: @@ -135,68 +617,78 @@ def start(request): msg = 'You do not have a profile and cannot take the quiz!' raise Http404(msg) - new_paper = QuestionPaper(user=user, user_ip=ip, key=key, - quiz=quiz, profile=profile) + 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() # Make user directory. user_dir = get_user_dir(user) - questions = [ str(_.id) for _ in Question.objects.filter(active=True) ] + questions = [str(_.id) for _ in questionpaper.questions.all()] random.shuffle(questions) - + + #questions = questionpaper.questions + #random.shuffle(questions) new_paper.questions = "|".join(questions) new_paper.save() - - # Show the user the intro page. - context = {'user': user} + # Show the user the intro page. + context = {'user': user, 'paper_id': questionpaper_id} ci = RequestContext(request) - return my_render_to_response('exam/intro.html', context, - context_instance=ci) + return my_render_to_response('exam/intro.html', context, + context_instance=ci) + + +def question(request, q_id, questionpaper_id): + """Check the credentials of the user and start the exam.""" -def question(request, q_id): user = request.user if not user.is_authenticated(): return my_redirect('/exam/login/') q = get_object_or_404(Question, pk=q_id) try: - paper = QuestionPaper.objects.get(user=request.user, quiz__active=True) - except QuestionPaper.DoesNotExist: - return my_redirect('/exam/start') - if not paper.quiz.active: + q_paper = QuestionPaper.objects.get(id=questionpaper_id) + paper = AnswerPaper.objects.get(\ + user=request.user, question_paper=q_paper) + except AnswerPaper.DoesNotExist: + return my_redirect('/exam/start/') + if not paper.question_paper.quiz.active: return complete(request, reason='The quiz has been deactivated!') time_left = paper.time_left() if time_left == 0: return complete(request, reason='Your time is up!') - quiz_name = paper.quiz.description - context = {'question': q, 'paper': paper, 'user': user, - 'quiz_name': quiz_name, + quiz_name = paper.question_paper.quiz.description + context = {'question': q, 'paper': paper, 'user': user, + 'quiz_name': quiz_name, 'time_left': time_left} ci = RequestContext(request) return my_render_to_response('exam/question.html', context, - context_instance=ci) + context_instance=ci) + -def show_question(request, q_id): +def show_question(request, q_id, questionpaper_id): """Show a question if possible.""" if len(q_id) == 0: msg = 'Congratulations! You have successfully completed the quiz.' return complete(request, msg) else: - return question(request, q_id) + return question(request, q_id, questionpaper_id) + + +def check(request, q_id, questionpaper_id=None): + """Checks the answers of the user for particular question""" -def check(request, q_id): user = request.user if not user.is_authenticated(): return my_redirect('/exam/login/') question = get_object_or_404(Question, pk=q_id) - paper = QuestionPaper.objects.get(user=user, quiz__active=True) + q_paper = QuestionPaper.objects.get(id=questionpaper_id) + paper = AnswerPaper.objects.get(user=request.user, question_paper=q_paper) answer = request.POST.get('answer') skip = request.POST.get('skip', None) - if skip is not None: next_q = paper.skip() - return show_question(request, next_q) + return show_question(request, next_q, questionpaper_id) # Add the answer submitted, regardless of it being correct or not. new_answer = Answer(question=question, answer=answer, correct=False) @@ -207,7 +699,7 @@ def check(request, q_id): # questions, we obtain the results via XML-RPC with the code executed # safely in a separate process (the code_server.py) running as nobody. if question.type == 'mcq': - success = True # Only one attempt allowed for MCQ's. + success = True # Only one attempt allowed for MCQ's. if answer.strip() == question.test.strip(): new_answer.correct = True new_answer.marks = question.points @@ -226,16 +718,15 @@ def check(request, q_id): new_answer.save() - if not success: # Should only happen for non-mcq questions. + if not success: # Should only happen for non-mcq questions. time_left = paper.time_left() if time_left == 0: return complete(request, reason='Your time is up!') - if not paper.quiz.active: + if not paper.question_paper.quiz.active: return complete(request, reason='The quiz has been deactivated!') - context = {'question': question, 'error_message': err_msg, 'paper': paper, 'last_attempt': answer, - 'quiz_name': paper.quiz.description, + 'quiz_name': paper.question_paper.quiz.description, 'time_left': time_left} ci = RequestContext(request) @@ -243,60 +734,76 @@ def check(request, q_id): context_instance=ci) else: next_q = paper.completed_question(question.id) - return show_question(request, next_q) - -def quit(request): - return my_render_to_response('exam/quit.html', - context_instance=RequestContext(request)) + return show_question(request, next_q, questionpaper_id) + + +def quit(request, answerpaper_id=None): + """Show the quit page when the user logs out.""" + context = {'id': answerpaper_id} + return my_render_to_response('exam/quit.html', context, + context_instance=RequestContext(request)) + + +def complete(request, reason=None, answerpaper_id=None): + """Show a page to inform user that the quiz has been compeleted.""" -def complete(request, reason=None): user = request.user + + if answerpaper_id is None: + logout(request) + context = {'message': "You are successfully Logged out."} + return my_render_to_response('exam/complete.html', context) no = False message = reason or 'The quiz has been completed. Thank you.' + if user.groups.filter(name='moderator').count() > 0: + message = 'You are successfully Logged out.' if request.method == 'POST' and 'no' in request.POST: - no = request.POST.get('no', False) + no = True if not no: # Logout the user and quit with the message given. - logout(request) - context = {'message': message} - return my_render_to_response('exam/complete.html', context) + answer_paper = AnswerPaper.objects.get(id=answerpaper_id) + answer_paper.endtime = datetime.datetime.now() + answer_paper.save() + return my_redirect('/exam/quizzes/') else: return my_redirect('/exam/') def monitor(request, quiz_id=None): """Monitor the progress of the papers taken so far.""" + user = request.user - if not user.is_authenticated() and not user.is_staff: + if not user.is_authenticated() or not is_moderator(user): raise Http404('You are not allowed to view this page!') if quiz_id is None: - quizzes = Quiz.objects.all() + q_paper = QuestionPaper.objects.all() context = {'papers': [], 'quiz': None, - 'quizzes':quizzes} + 'quizzes': q_paper} return my_render_to_response('exam/monitor.html', context, context_instance=RequestContext(request)) # quiz_id is not None. try: - quiz = Quiz.objects.get(id=quiz_id) - except Quiz.DoesNotExist: + quiz = QuestionPaper.objects.get(id=quiz_id) + except QuestionPaper.DoesNotExist: papers = [] quiz = None else: - papers = QuestionPaper.objects.all().annotate( + papers = AnswerPaper.objects.all().annotate( total=Sum('answers__marks')).order_by('-total') context = {'papers': papers, 'quiz': quiz, 'quizzes': None} return my_render_to_response('exam/monitor.html', context, context_instance=RequestContext(request)) + def get_user_data(username): """For a given username, this returns a dictionary of important data related to the user including all the user's answers submitted. """ user = User.objects.get(username=username) - papers = QuestionPaper.objects.filter(user=user) + papers = AnswerPaper.objects.filter(user=user) data = {} try: @@ -309,10 +816,144 @@ def get_user_data(username): data['papers'] = papers return data + +def show_all_users(request): + """Shows all the users who have taken various exams/quiz.""" + + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page !') + user = User.objects.filter(username__contains="") + questionpaper = AnswerPaper.objects.all() + context = {'question': questionpaper} + return my_render_to_response('exam/showusers.html', context, + context_instance=RequestContext(request)) + + +def show_all_quiz(request): + """Generates a list of all the quizzes + that are currently in the database.""" + + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404('You are not allowed to view this page !') + + if request.method == 'POST' and request.POST.get('delete') == 'delete': + data = request.POST.getlist('quiz') + + if data is None: + quizzes = Quiz.objects.all() + context = {'papers': [], + 'quiz': None, + 'quizzes': quizzes} + return my_render_to_response('exam/show_quiz.html', context, + context_instance=RequestContext(request)) + else: + for i in data: + quiz = Quiz.objects.get(id=i).delete() + quizzes = Quiz.objects.all() + context = {'papers': [], + 'quiz': None, + 'quizzes': quizzes} + return my_render_to_response('exam/show_quiz.html', context, + context_instance=RequestContext(request)) + + elif request.method == 'POST' and request.POST.get('edit') == 'edit': + data = request.POST.getlist('quiz') + forms = [] + for j in data: + d = Quiz.objects.get(id=j) + form = QuizForm() + form.initial['start_date'] = d.start_date + 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}, + context_instance=RequestContext(request)) + else: + quizzes = Quiz.objects.all() + context = {'papers': [], + 'quiz': None, + 'quizzes': quizzes} + return my_render_to_response('exam/show_quiz.html', context, + context_instance=RequestContext(request)) + + +def show_all_questions(request): + """Show a list of all the questions currently in the databse.""" + + user = request.user + if not user.is_authenticated() or not is_moderator(user): + raise Http404("You are not allowed to view this page !") + + if request.method == 'POST' and request.POST.get('delete') == 'delete': + data = request.POST.getlist('question') + if data is None: + questions = Question.objects.all() + context = {'papers': [], + 'question': None, + 'questions': questions} + return my_render_to_response('exam/showquestions.html', context, + context_instance=RequestContext(request)) + else: + for i in data: + question = Question.objects.get(id=i).delete() + questions = Question.objects.all() + context = {'papers': [], + 'question': None, + 'questions': questions} + return my_render_to_response('exam/showquestions.html', context, + context_instance=RequestContext(request)) + elif request.method == 'POST' and request.POST.get('edit') == 'edit': + data = request.POST.getlist('question') + + forms = [] + for j in data: + d = Question.objects.get(id=j) + form = QuestionForm() + form.initial['summary'] = d.summary + form.initial['description'] = d.description + form.initial['points'] = d.points + form.initial['test'] = d.test + form.initial['options'] = d.options + form.initial['type'] = d.type + 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 + forms.append(form) + return my_render_to_response('exam/edit_question.html', + {'forms': forms, 'data': data}, + context_instance=RequestContext(request)) + else: + questions = Question.objects.all() + context = {'papers': [], + 'question': None, + 'questions': questions} + return my_render_to_response('exam/showquestions.html', context, + context_instance=RequestContext(request)) + + def user_data(request, username): """Render user data.""" + current_user = request.user - if not current_user.is_authenticated() and not current_user.is_staff: + if not current_user.is_authenticated() or not is_moderator(user): raise Http404('You are not allowed to view this page!') data = get_user_data(username) @@ -321,12 +962,13 @@ def user_data(request, username): return my_render_to_response('exam/user_data.html', context, context_instance=RequestContext(request)) + def grade_user(request, username): """Present an interface with which we can easily grade a user's papers and update all their marks and also give comments for each paper. """ current_user = request.user - if not current_user.is_authenticated() and not current_user.is_staff: + if not current_user.is_authenticated() or not is_moderator(current_user): raise Http404('You are not allowed to view this page!') data = get_user_data(username) @@ -334,11 +976,12 @@ def grade_user(request, username): papers = data['papers'] for paper in papers: for question, answers in paper.get_question_answers().iteritems(): - marks = float(request.POST.get('q%d_marks'%question.id)) + marks = float(request.POST.get('q%d_marks' % question.id)) last_ans = answers[-1] last_ans.marks = marks last_ans.save() - paper.comments = request.POST.get('comments_%d'%paper.quiz.id) + paper.comments = request.POST.get(\ + 'comments_%d' % paper.question_paper.id) paper.save() context = {'data': data} @@ -348,4 +991,3 @@ def grade_user(request, username): context = {'data': data} return my_render_to_response('exam/grade_user.html', context, context_instance=RequestContext(request)) - |