summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrabhu Ramachandran2016-05-04 18:31:28 +0530
committerPrabhu Ramachandran2016-05-04 18:31:28 +0530
commit8841e5ed4f8f79b7067ddb3523f4a3ec50f362b3 (patch)
treea9db341f13abdf47f994d8823f233219561dbff2
parent03f0aa839e4d91a3d83d68d5301f1425f18cca73 (diff)
parentf150f1c54ee5941d72f2e4057af8c90cca588292 (diff)
downloadonline_test-8841e5ed4f8f79b7067ddb3523f4a3ec50f362b3.tar.gz
online_test-8841e5ed4f8f79b7067ddb3523f4a3ec50f362b3.tar.bz2
online_test-8841e5ed4f8f79b7067ddb3523f4a3ec50f362b3.zip
Merge pull request #97 from maheshgudi/grade_user_2
Grade User
-rw-r--r--yaksh/models.py51
-rw-r--r--yaksh/static/yaksh/css/gradeuser.css8
-rw-r--r--yaksh/templates/yaksh/grade_user.html110
-rw-r--r--yaksh/templates/yaksh/monitor.html10
-rw-r--r--yaksh/templates/yaksh/user_data.html15
-rw-r--r--yaksh/tests.py12
-rw-r--r--yaksh/urls.py12
-rw-r--r--yaksh/views.py80
8 files changed, 212 insertions, 86 deletions
diff --git a/yaksh/models.py b/yaksh/models.py
index a4ea6c3..561b334 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -235,10 +235,15 @@ class Answer(models.Model):
# Whether skipped or not.
skipped = models.BooleanField(default=False)
+ def set_marks(self, marks):
+ if marks > self.question.points:
+ self.marks = self.question.points
+ else:
+ self.marks = marks
+
def __unicode__(self):
return self.answer
-
###############################################################################
class QuizManager(models.Manager):
def get_active_quizzes(self):
@@ -470,8 +475,13 @@ class AnswerPaperManager(models.Manager):
question_stats[question] = [0, questions[question.id]]
return question_stats
- def get_answerpapers_for_quiz(self, questionpaper_id):
- return self.filter(question_paper_id=questionpaper_id)
+ def _get_answerpapers_for_quiz(self, questionpaper_id, status=False):
+ if not status:
+ return self.filter(question_paper_id=questionpaper_id)
+ else:
+ return self.filter(question_paper_id=questionpaper_id,
+ status="completed")
+
def _get_answerpapers_users(self, answerpapers):
return answerpapers.values_list('user', flat=True).distinct()
@@ -499,6 +509,31 @@ class AnswerPaperManager(models.Manager):
def get_total_attempt(self, questionpaper, user):
return self.filter(question_paper=questionpaper, user=user).count()
+ def get_users_for_questionpaper(self, questionpaper_id):
+ return self._get_answerpapers_for_quiz(questionpaper_id, status=True)\
+ .values("user__id", "user__first_name", "user__last_name")\
+ .distinct()
+
+ def get_user_all_attempts(self, questionpaper, user):
+ return self.filter(question_paper=questionpaper, user=user)\
+ .order_by('-attempt_number')
+
+ def get_user_data(self, user, questionpaper_id, attempt_number=None):
+ if attempt_number is not None:
+ papers = self.filter(user=user, question_paper_id=questionpaper_id,
+ attempt_number=attempt_number)
+ else:
+ papers = self.filter(user=user, question_paper_id=questionpaper_id)\
+ .order_by("-attempt_number")
+ data = {}
+ profile = user.profile if hasattr(user, 'profile') else None
+ data['user'] = user
+ data['profile'] = profile
+ data['papers'] = papers
+ data['questionpaperid'] = questionpaper_id
+ return data
+
+
###############################################################################
class AnswerPaper(models.Model):
"""A answer paper for a student -- one per student typically.
@@ -563,7 +598,7 @@ class AnswerPaper(models.Model):
def completed_question(self, question_id):
"""
- Adds the completed question to the list of answered
+ Adds the completed question to the list of answered
questions and returns the next question.
"""
self.questions_answered.add(question_id)
@@ -629,7 +664,11 @@ class AnswerPaper(models.Model):
self._update_percent()
self._update_passed()
self._update_status(state)
- self.end_time = datetime.now()
+ self.save()
+
+ def set_end_time(self, datetime):
+ """ Sets end time """
+ self.end_time = datetime
self.save()
def get_question_answers(self):
@@ -695,5 +734,3 @@ class TestCase(models.Model):
# Test case Expected answer in list form
expected_answer = models.TextField(blank=True, null = True)
-
-
diff --git a/yaksh/static/yaksh/css/gradeuser.css b/yaksh/static/yaksh/css/gradeuser.css
index 07b1079..af5de3f 100644
--- a/yaksh/static/yaksh/css/gradeuser.css
+++ b/yaksh/static/yaksh/css/gradeuser.css
@@ -36,7 +36,7 @@ color: #9EB6FF;
border: 1px solid #C9C9C9;
border-radius: 5px 5px 5px 5px;
margin-bottom: 10px;
- min-width: 805px;
+ min-width: 685px;
}
@@ -50,3 +50,9 @@ margin: 10px 10px 5px 5px;
}
#headerDiv a:hover {
color: #FFFFFF;
+}
+
+#attempt {
+ width: 157px;
+ position: relative; left:20%;
+}
diff --git a/yaksh/templates/yaksh/grade_user.html b/yaksh/templates/yaksh/grade_user.html
index dd05670..2c5403c 100644
--- a/yaksh/templates/yaksh/grade_user.html
+++ b/yaksh/templates/yaksh/grade_user.html
@@ -1,46 +1,101 @@
{% extends "manage.html" %}
-{% block title %} Grading papers for {{ data.user.get_full_name.title }} {% endblock title %}
+{% block title %} Grade User {% endblock title %}
-{% block subtitle %}Grading papers for {{ data.user.get_full_name.title }}{% endblock %}
+{% block subtitle %} Grade User {% endblock %}
{% block css %}
- <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/gradeuser.css" type="text/css" />
+ <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/gradeuser.css" type="text/css" />
{% endblock %}
{% block script %}
-<script src= "{{ URL_ROOT }}/static/yaksh/js/edit_question.js"></script>
+ <script src= "{{ URL_ROOT }}/static/yaksh/js/edit_question.js"></script>
{% endblock %}
+
{% block manage %}
-<p>
-Name: {{ data.user.get_full_name.title }}
+{% if course_details %}
+ <table id = "course-details" class = "zebra-striped">
+ <tr>
+ <th>Courses</th>
+ <th> Quizzes </th>
+ </tr>
+
+ {% for course in course_details %}
+ <tr>
+ <td><ul>{{course.name}} </td>
+
+ {% if course.get_quizzes %}
+ <td>
+ {% for quiz in course.get_quizzes %}
+ <li><a href = "{{URL_ROOT}}/exam/manage/gradeuser/{{quiz.id}}">{{quiz.description}}</a></li>
+
+ {% endfor %}
+ </td>
+ {% else %}
+ <td> No quiz</td>
+ {% endif %}
+ </ul></tr>
+ {% endfor %}
+ </table>
+{% endif %}
+
+<div class="row">
+{%if users %}
+ <div id = "student" class="span2">
+ {% for user in users %}
+ <p><a href = "{{URL_ROOT}}/exam/manage/gradeuser/{{quiz_id}}/{{user.user__id}}">{{user.user__first_name}} {{user.user__last_name}}</a></p>
+ {% endfor %}
+ </div>
+{% endif %}
+
+
+
+<div id = "paper" class="span12">
+{% if data %}
+
+
+<p> <h3> <center> Showing paper for {{data.user.get_full_name.title}} </center></h3>
+<p><b>Name:</b>{{ data.user.get_full_name.title }}
{% if data.profile %}
-(roll number: {{ data.profile.roll_number }}) <br/>
-Position: {{ data.profile.position }} <br/>
-Department: {{ data.profile.department }} <br/>
-Institute: {{ data.profile.institute }} <br/>
+
+<p><b> Roll number:</b> {{ data.profile.roll_number }}
+<p><b>Position: </b> {{ data.profile.position }}
+<p><b>Department: </b>{{ data.profile.department }}
+<p><b>Institute: </b>{{ data.profile.institute }}
{% endif %}
-</p>
{% if data.papers %}
{% for paper in data.papers %}
-
-{% if forloop.counter == 2 and data.questionpaperid %}
<hr>
-<u><h2> Previous attempts </h2></u>
-{% endif %}
{{ paper.total_marks }}
-<h2> Quiz: {{ paper.question_paper.quiz.description }} </h2>
+<h3> Quiz: {{ paper.question_paper.quiz.description }} </h3>
<p>
-Attempt Number: {{ paper.attempt_number }}<br/>
-Questions correctly answered: {{ paper.get_answered_str }} <br/>
+Attempt Number: <b>{{paper.attempt_number}} </b>
+<select id = "attempt" onchange="window.location.href=this.value">
+<option selected="">Select attempt number</option>
+{%for attempt in attempts %}
+<option value = "{{URL_ROOT}}/exam/manage/gradeuser/{{quiz_id}}/{{user_id}}/{{attempt.attempt_number}}/">
+{{attempt.attempt_number}}
+</option>
+{% endfor %}
+</select>
+
+<br/>Questions correctly answered: {{ paper.get_answered_str }} <br/>
Total attempts at questions: {{ paper.answers.count }} <br/>
-Marks obtained: {{ paper.get_total_marks }} <br/>
+Marks obtained: {{ paper.marks_obtained }} <br/>
Start time: {{ paper.start_time }} <br/>
+{%if paper.percent%}
+Percentage obtained: {{paper.percent}}% <br/>
+{% endif %}
+{% if paper.passed == 0 %}
+Status : <b style="color: red;"> Failed </b><br/>
+{% else %}
+Status : <b style="color: green;"> Passed </b><br/>
+{% endif %}
</p>
{% if paper.answers.count %}
@@ -59,12 +114,13 @@ Start time: {{ paper.start_time }} <br/>
{% endfor %}
</table>
+
<h3> Answers </h3><br>
<form name=frm id="q{{ paper.quiz.id }}_form"
{% if data.questionpaperid %}
- action="{{URL_ROOT}}/exam/manage/gradeuser/{{data.user.username}}/{{data.questionpaperid}}/"
+ action="{{URL_ROOT}}/exam/manage/gradeuser/{{quiz_id}}/{{user_id}}/{{paper.attempt_number}}/"
{% else %}
- action="{{URL_ROOT}}/exam/manage/gradeuser/{{data.user.username}}/"
+ action="{{URL_ROOT}}/exam/manage/gradeuser/{{quiz_id}}/{{user_id}}/{{paper.attempt_number}}/"
{% endif %}
method="post">
{% csrf_token %}
@@ -72,13 +128,13 @@ Start time: {{ paper.start_time }} <br/>
<div class="for-question">
<p><strong>
- Question: {{ question.id }}. {{ question.summary }} (Points: {{ question.points }})
+ Question: {{ question.id }}. {{ question.summary }} (Points: {{ question.points }})
</strong>
<strong><a href="" onClick="grade_data('myContent{{question.id}}'); return false;" style="cursor:pointer;" />Details</strong></p></a>
<div id="contentDiv">
<div id="myContent{{question.id}}" style="padding:5px; display:none;">
<p> Description : {{ question.description }} </p>
- <p> Test : {{ question.test }} </p>
+ <p> Test : {{ question.test }} </p>
</div>
</div>
<div class="question-form">
@@ -113,10 +169,16 @@ Marks: <input id="q{{ question.id }}" type="text"
<br><button class="btn" type="submit" name="submit_{{paper.quiz.id}}">Save Marks</button>
</form>
+</div>
+
{% endif %} {# if paper.answers.count #}
{% endfor %} {# for paper in data.papers #}
-{% endif %} {# if data.papers #}
+{% endif %} {# if data.papers #}
+{% else %}
+ </div>
+{% endif %} {#if data#}
+</div>
{% endblock%}
diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html
index b81c9f2..80ad06c 100644
--- a/yaksh/templates/yaksh/monitor.html
+++ b/yaksh/templates/yaksh/monitor.html
@@ -9,13 +9,13 @@
{% endblock %}
{% block subtitle %}
{% if not quizzes and not quiz %}
- Quiz Results
+ Quiz Results
{% endif %}
{% if quizzes %}
- Available Quizzes
+ Available Quizzes
{% endif %}
{% if quiz %}
- {{ quiz.description }} Results
+ {{ quiz.description }} Results
{% endif %}
{% endblock %}
{% block manage %}
@@ -54,7 +54,7 @@
</tr>
{% for paper in latest_attempts %}
<tr>
- <td> <a href="{{URL_ROOT}}/exam/manage/user_data/{{paper.user.username}}/{{paper.question_paper.id}}">{{ paper.user.get_full_name.title }}</a> </td>
+ <td> <a href="{{URL_ROOT}}/exam/manage/user_data/{{paper.user.id}}/{{paper.question_paper.id}}">{{ paper.user.get_full_name.title }}</a> </td>
<td> {{ paper.user.username }} </td>
<td> {{ paper.user.profile.roll_number }} </td>
<td> {{ paper.user.profile.institute }} </td>
@@ -69,4 +69,4 @@
<p> No answer papers so far. </p>
{% endif %} {# if papers #}
{% endif %}
-{% endblock %}
+{% endblock %} \ No newline at end of file
diff --git a/yaksh/templates/yaksh/user_data.html b/yaksh/templates/yaksh/user_data.html
index 22be3ed..04544f9 100644
--- a/yaksh/templates/yaksh/user_data.html
+++ b/yaksh/templates/yaksh/user_data.html
@@ -22,11 +22,11 @@ Last login: {{ data.user.last_login }}
{% if data.papers %}
{% if data.questionpaperid %}
-<p><a href="{{URL_ROOT}}/exam/manage/gradeuser/{{ data.user.username }}/{{ data.questionpaperid }}">
+<p><a href="{{URL_ROOT}}/exam/manage/gradeuser/{{data.papers.0.question_paper.quiz.id}}/{{ data.user.id }}">
Grade/correct paper</a>
</p>
{% else %}
-<p><a href="{{URL_ROOT}}/exam/manage/gradeuser/{{ data.user.username }}">
+<p><a href="{{URL_ROOT}}/exam/manage/gradeuser/{{data.papers.0.question_paper.quiz.id}}/{{ data.user.id }}">
Grade/correct paper</a>
{% endif %}
@@ -41,7 +41,7 @@ Last login: {{ data.user.last_login }}
Attempt Number: {{ paper.attempt_number }}<br/>
Questions correctly answered: {{ paper.get_answered_str }} <br/>
Total attempts at questions: {{ paper.answers.count }} <br/>
-Marks obtained: {{ paper.get_total_marks }} <br/>
+Marks obtained: {{ paper.marks_obtained }} <br/>
Start time: {{ paper.start_time }} <br/>
User IP address: {{ paper.user_ip }}
</p>
@@ -75,9 +75,12 @@ User IP address: {{ paper.user_ip }}
{% endif %} {# if data.papers #}
<br />
<hr />
-<a href="{{URL_ROOT}}/exam/manage/gradeuser/{{ data.user.username }}/">
- Grade/correct paper</a>
-<br/>
+
+{% with data.papers.0 as paper %}
+<a href="{{URL_ROOT}}/exam/manage/gradeuser/{{paper.question_paper.quiz.id}}/{{ data.user.id }}/">Grade/correct paper</a>
+{% endwith %}
+<br />
+
{% if data.papers.count > 1 %}
<a href="{{URL_ROOT}}/exam/manage/monitor/">Monitor quiz</a>
{% else %}
diff --git a/yaksh/tests.py b/yaksh/tests.py
index cc3100e..d3ff4fc 100644
--- a/yaksh/tests.py
+++ b/yaksh/tests.py
@@ -355,6 +355,11 @@ class AnswerPaperTestCases(unittest.TestCase):
self.assertTrue(self.answerpaper.passed)
self.assertFalse(self.answerpaper.is_attempt_inprogress())
+ def test_set_end_time(self):
+ current_time = datetime.now()
+ self.answerpaper.set_end_time(current_time)
+ self.assertEqual(self.answerpaper.end_time,current_time)
+
def test_get_question_answer(self):
""" Test get_question_answer() method of Answer Paper"""
answered = self.answerpaper.get_question_answers()
@@ -375,6 +380,13 @@ class AnswerPaperTestCases(unittest.TestCase):
self.assertEqual(answers.count(), 1)
self.assertTrue(answers[0], self.answer_wrong)
+ def test_set_marks (self):
+ self.answer_wrong.set_marks(0.5)
+ self.assertEqual(self.answer_wrong.marks, 0.5)
+ self.answer_wrong.set_marks(10.0)
+ self.assertEqual(self.answer_wrong.marks,1.0)
+
+
###############################################################################
class CourseTestCases(unittest.TestCase):
def setUp(self):
diff --git a/yaksh/urls.py b/yaksh/urls.py
index ea1922d..b32bc36 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -44,19 +44,19 @@ urlpatterns += [
url(r'^manage/addquestion/(?P<question_id>\d+)/$', views.add_question),
url(r'^manage/addquiz/$', views.add_quiz),
url(r'^manage/addquiz/(?P<quiz_id>\d+)/$', views.add_quiz),
- url(r'^manage/gradeuser/$', views.show_all_users),
- url(r'^manage/gradeuser/(?P<username>.*)/(?P<questionpaper_id>\d+)/$',
- views.grade_user),
- url(r'^manage/gradeuser/(?P<username>.*)/$', views.grade_user),
+ url(r'^manage/gradeuser/$', views.grade_user),
+ url(r'^manage/gradeuser/(?P<quiz_id>\d+)/$',views.grade_user),
+ url(r'^manage/gradeuser/(?P<quiz_id>\d+)/(?P<user_id>\d+)/$',views.grade_user),
+ url(r'^manage/gradeuser/(?P<quiz_id>\d+)/(?P<user_id>\d+)/(?P<attempt_number>\d+)/$',views.grade_user),
url(r'^manage/questions/$', views.show_all_questions),
url(r'^manage/monitor/$', views.monitor),
url(r'^manage/showquestionpapers/$', views.show_all_questionpapers),
url(r'^manage/showquestionpapers/(?P<questionpaper_id>\d+)/$',\
views.show_all_questionpapers),
url(r'^manage/monitor/(?P<questionpaper_id>\d+)/$', views.monitor),
- url(r'^manage/user_data/(?P<username>.*)/(?P<questionpaper_id>\d+)/$',
+ url(r'^manage/user_data/(?P<user_id>\d+)/(?P<questionpaper_id>\d+)/$',
views.user_data),
- url(r'^manage/user_data/(?P<username>.*)/$', views.user_data),
+ url(r'^manage/user_data/(?P<user_id>\d+)/$', views.user_data),
url(r'^manage/designquestionpaper/$', views.design_questionpaper),
url(r'^manage/designquestionpaper/(?P<questionpaper_id>\d+)/$',\
views.design_questionpaper),
diff --git a/yaksh/views.py b/yaksh/views.py
index 5cc9f99..a91da29 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -3,7 +3,7 @@ import string
import os
import stat
from os.path import dirname, pardir, abspath, join, exists
-import datetime
+from datetime import datetime
import collections
import csv
from django.http import HttpResponse
@@ -472,6 +472,7 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
new_answer.error = result.get('error')
new_answer.save()
paper.update_marks('inprogress')
+ paper.set_end_time(datetime.now())
if not result.get('success'): # Should only happen for non-mcq questions.
new_answer.answer = user_code
new_answer.save()
@@ -548,6 +549,7 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None):
paper = AnswerPaper.objects.get(user=user, question_paper=q_paper,
attempt_number=attempt_num)
paper.update_marks()
+ paper.set_end_time(datetime.now())
if paper.percent == 100:
message = "You answered all the questions correctly.\
You have been logged out successfully,\
@@ -760,25 +762,6 @@ def monitor(request, questionpaper_id=None):
context_instance=ci)
-def get_user_data(username, questionpaper_id=None):
- """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 = AnswerPaper.objects.filter(user=user)
- if questionpaper_id is not None:
- papers = papers.filter(question_paper_id=questionpaper_id).order_by(
- '-attempt_number')
-
- data = {}
- profile = user.profile if hasattr(user, 'profile') else None
- data['user'] = user
- data['profile'] = profile
- data['papers'] = papers
- data['questionpaperid'] = questionpaper_id
- return data
-
-
@login_required
def show_all_users(request):
"""Shows all the users who have taken various exams/quiz."""
@@ -842,14 +825,13 @@ def show_all_questions(request):
context_instance=ci)
@login_required
-def user_data(request, username, questionpaper_id=None):
+def user_data(request, user_id, questionpaper_id=None):
"""Render user data."""
-
current_user = request.user
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, questionpaper_id)
+ user = User.objects.get(id=user_id)
+ data = AnswerPaper.objects.get_user_data(user, questionpaper_id)
context = {'data': data}
return my_render_to_response('yaksh/user_data.html', context,
@@ -903,7 +885,7 @@ def download_csv(request, questionpaper_id):
@login_required
-def grade_user(request, username, questionpaper_id=None):
+def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
"""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.
"""
@@ -911,26 +893,50 @@ def grade_user(request, username, questionpaper_id=None):
ci = RequestContext(request)
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, questionpaper_id)
- if request.method == 'POST':
+ course_details = Course.objects.filter(Q(creator=current_user)|
+ Q(teachers=current_user)).distinct()
+ context = {"course_details": course_details}
+ if quiz_id is not None:
+ questionpaper_id = QuestionPaper.objects.filter(quiz_id=quiz_id)\
+ .values("id")
+ user_details = AnswerPaper.objects.get_users_for_questionpaper\
+ (questionpaper_id)
+ context = {"users": user_details, "quiz_id": quiz_id}
+ if user_id is not None:
+
+ attempts = AnswerPaper.objects.get_user_all_attempts\
+ (questionpaper_id, user_id)
+ try:
+ if attempt_number is None:
+ attempt_number = attempts[0].attempt_number
+ except IndexError:
+ raise Http404('No attempts for paper')
+
+ user = User.objects.get(id=user_id)
+ data = AnswerPaper.objects.get_user_data(user, questionpaper_id,
+ attempt_number
+ )
+
+ context = {'data': data, "quiz_id": quiz_id, "users": user_details,
+ "attempts": attempts, "user_id": user_id
+ }
+ if request.method == "POST":
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, 0))
- last_ans = answers[-1]
- last_ans.marks = marks
- last_ans.save()
+ answers = answers[-1]
+ answers.set_marks(marks)
+ answers.save()
+ paper.update_marks()
paper.comments = request.POST.get(
'comments_%d' % paper.question_paper.id, 'No comments')
paper.save()
- context = {'data': data}
- return my_render_to_response('yaksh/user_data.html', context,
- context_instance=ci)
- else:
- context = {'data': data}
- return my_render_to_response('yaksh/grade_user.html', context,
- context_instance=ci)
+
+ return my_render_to_response('yaksh/grade_user.html',
+ context, context_instance=ci
+ )
@csrf_exempt