summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
authorPrabhu Ramachandran2016-01-22 20:09:20 +0530
committerPrabhu Ramachandran2016-01-22 20:09:20 +0530
commitb626dbd94ea6342e5257bd5c79d47e9821b3fdde (patch)
tree69bce77f8417479e16f8e824da3d972e3287c79a /yaksh
parent3f037c26bc5c09ddfbd24930148233535770b38b (diff)
parent45163b0a4de5b685c5fd57dea6abd51d4c343a35 (diff)
downloadonline_test-b626dbd94ea6342e5257bd5c79d47e9821b3fdde.tar.gz
online_test-b626dbd94ea6342e5257bd5c79d47e9821b3fdde.tar.bz2
online_test-b626dbd94ea6342e5257bd5c79d47e9821b3fdde.zip
Merge pull request #66 from ankitjavalkar/concurrent-login
Allow single user session active at any given time
Diffstat (limited to 'yaksh')
-rw-r--r--yaksh/middleware/__init__.py0
-rw-r--r--yaksh/middleware/one_session_per_user.py35
-rw-r--r--yaksh/models.py6
-rw-r--r--yaksh/urls.py2
-rw-r--r--yaksh/views.py28
5 files changed, 68 insertions, 3 deletions
diff --git a/yaksh/middleware/__init__.py b/yaksh/middleware/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/yaksh/middleware/__init__.py
diff --git a/yaksh/middleware/one_session_per_user.py b/yaksh/middleware/one_session_per_user.py
new file mode 100644
index 0000000..92e888d
--- /dev/null
+++ b/yaksh/middleware/one_session_per_user.py
@@ -0,0 +1,35 @@
+from django.contrib.auth.models import User
+from django.contrib.sessions.models import Session
+
+from yaksh.models import ConcurrentUser
+
+
+class OneSessionPerUserMiddleware(object):
+ """
+ Middleware to handle multiple logins with same credentials
+ - Creates a Database entry to record the current user and active session key
+ - Checks if the current user has already been logged in. If True, the new session
+ key is stored with respect to the user and the old session key is deleted,
+ effectively terminating the older session for the same user.
+ - The concurrentuser attribute of the User model refers to the ConcurrentUser
+ model object and not the concurrent_user field due to behaviour described
+ in the Documentation
+ Link: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#extending-the-existing-user-model)
+ """
+ def process_request(self, request):
+ if isinstance(request.user, User):
+ current_key = request.session.session_key
+ #
+ # Documentation:
+ # https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#extending-the-existing-user-model
+ if hasattr(request.user, 'concurrentuser'):
+ active_key = request.user.concurrentuser.session_key
+ if active_key != current_key:
+ Session.objects.filter(session_key=active_key).delete()
+ request.user.concurrentuser.session_key = current_key
+ request.user.concurrentuser.save()
+ else:
+ ConcurrentUser.objects.create(
+ concurrent_user=request.user,
+ session_key=current_key,
+ ) \ No newline at end of file
diff --git a/yaksh/models.py b/yaksh/models.py
index 62ac9bc..e7852d5 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -8,6 +8,12 @@ from taggit.managers import TaggableManager
###############################################################################
+class ConcurrentUser(models.Model):
+ concurrent_user = models.OneToOneField(User, null=False)
+ session_key = models.CharField(null=False, max_length=40)
+
+
+###############################################################################
class Profile(models.Model):
"""Profile for a user to store roll number and other details."""
user = models.OneToOneField(User)
diff --git a/yaksh/urls.py b/yaksh/urls.py
index a9f7a98..66159f0 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -47,6 +47,6 @@ urlpatterns = patterns('yaksh.views',
url(r'^manage/designquestionpaper/manual/(?P<questionpaper_id>\d+)/$',\
'manual_questionpaper'),
url(r'^ajax/questionpaper/(?P<query>.+)/$', 'ajax_questionpaper'),
- url(r'^ajax/questions/filter/$', 'ajax_questions_filter'), ##@@
+ url(r'^ajax/questions/filter/$', 'ajax_questions_filter'),
)
diff --git a/yaksh/views.py b/yaksh/views.py
index 41ce1bb..99e9f3b 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -12,6 +12,7 @@ from django.template import RequestContext
from django.http import Http404
from django.db.models import Sum
from django.views.decorators.csrf import csrf_exempt
+from django.contrib.auth.decorators import login_required
from taggit.models import Tag
from itertools import chain
import json
@@ -136,6 +137,7 @@ def user_register(request):
context_instance=ci)
+@login_required
def quizlist_user(request):
"""Show All Quizzes that is available to logged-in user."""
user = request.user
@@ -164,7 +166,7 @@ def quizlist_user(request):
return my_render_to_response("yaksh/quizzes_user.html", context)
-
+@login_required
def intro(request, questionpaper_id):
"""Show introduction page before quiz starts"""
user = request.user
@@ -253,7 +255,7 @@ def _check_previous_attempt(attempted_papers, already_attempted, attempt_number)
else:
return False, previous_attempt, next_attempt
-
+@login_required
def results_user(request):
"""Show list of Results of Quizzes that is taken by logged-in user."""
user = request.user
@@ -270,6 +272,7 @@ def results_user(request):
return my_render_to_response("yaksh/results_user.html", context)
+@login_required
def edit_quiz(request):
"""Edit the list of quizzes seleted by the user for editing."""
@@ -304,6 +307,7 @@ def edit_quiz(request):
return my_redirect("/exam/manage/showquiz/")
+@login_required
def edit_question(request):
"""Edit the list of questions selected by the user for editing."""
user = request.user
@@ -341,6 +345,7 @@ def edit_question(request):
return my_redirect("/exam/manage/questions")
+@login_required
def add_question(request, question_id=None):
"""To add a new question in the database.
Create a new question and store it."""
@@ -475,6 +480,7 @@ def add_question(request, question_id=None):
context_instance=ci)
+@login_required
def add_quiz(request, quiz_id=None):
"""To add a new quiz in the database.
Create a new quiz and store it."""
@@ -540,6 +546,7 @@ def add_quiz(request, quiz_id=None):
context_instance=ci)
+@login_required
def show_all_questionpapers(request, questionpaper_id=None):
user = request.user
ci = RequestContext(request)
@@ -573,6 +580,7 @@ def show_all_questionpapers(request, questionpaper_id=None):
context_instance=ci)
+@login_required
def automatic_questionpaper(request, questionpaper_id=None):
"""Generate automatic question paper for a particular quiz"""
@@ -664,6 +672,7 @@ def automatic_questionpaper(request, questionpaper_id=None):
context, context_instance=ci)
+@login_required
def manual_questionpaper(request, questionpaper_id=None):
user = request.user
ci = RequestContext(request)
@@ -739,6 +748,7 @@ def manual_questionpaper(request, questionpaper_id=None):
context, context_instance=ci)
+@login_required
def prof_manage(request):
"""Take credentials of the user with professor/moderator
rights/permissions and log in."""
@@ -788,6 +798,7 @@ def user_login(request):
context_instance=ci)
+@login_required
def start(request, attempt_num=None, questionpaper_id=None):
"""Check the user cedentials and if any quiz is available,
start the exam."""
@@ -822,6 +833,7 @@ def start(request, attempt_num=None, questionpaper_id=None):
user_dir = get_user_dir(user)
return start(request, attempt_num, questionpaper_id)
+@login_required
def get_questions(paper):
'''
Takes answerpaper as an argument. Returns the total questions as
@@ -848,6 +860,7 @@ def get_questions(paper):
return questions, to_attempt, submitted
+@login_required
def question(request, q_id, attempt_num, questionpaper_id, success_msg=None):
"""Check the credentials of the user and start the exam."""
@@ -890,6 +903,7 @@ def question(request, q_id, attempt_num, questionpaper_id, success_msg=None):
context_instance=ci)
+@login_required
def show_question(request, q_id, attempt_num, questionpaper_id, success_msg=None):
"""Show a question if possible."""
user = request.user
@@ -927,6 +941,7 @@ def _save_skipped_answer(old_skipped, user_answer, paper, question):
skipped_answer.save()
paper.answers.add(skipped_answer)
+
def check(request, q_id, attempt_num=None, questionpaper_id=None):
"""Checks the answers of the user for particular question"""
@@ -1109,6 +1124,7 @@ def quit(request, attempt_num=None, questionpaper_id=None):
context_instance=RequestContext(request))
+@login_required
def complete(request, reason=None, attempt_num=None, questionpaper_id=None):
"""Show a page to inform user that the quiz has been compeleted."""
@@ -1162,6 +1178,7 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None):
return my_redirect('/exam/')
+@login_required
def monitor(request, questionpaper_id=None):
"""Monitor the progress of the papers taken so far."""
@@ -1192,6 +1209,7 @@ def monitor(request, questionpaper_id=None):
context_instance=ci)
+@login_required
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.
@@ -1211,6 +1229,7 @@ def get_user_data(username):
return data
+@login_required
def show_all_users(request):
"""Shows all the users who have taken various exams/quiz."""
@@ -1224,6 +1243,7 @@ def show_all_users(request):
context_instance=RequestContext(request))
+@login_required
def show_all_quiz(request):
"""Generates a list of all the quizzes
that are currently in the database."""
@@ -1306,6 +1326,7 @@ def ajax_questions_filter(request):
{'questions': questions})
+@login_required
def show_all_questions(request):
"""Show a list of all the questions currently in the databse."""
@@ -1385,6 +1406,7 @@ def show_all_questions(request):
context_instance=ci)
+@login_required
def user_data(request, username):
"""Render user data."""
@@ -1399,6 +1421,7 @@ def user_data(request, username):
context_instance=RequestContext(request))
+@login_required
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.
@@ -1456,6 +1479,7 @@ def ajax_questionpaper(request, query):
{'questions': questions})
+@login_required
def design_questionpaper(request):
user = request.user
ci = RequestContext(request)