summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yaksh/models.py3
-rw-r--r--yaksh/templates/base.html1
-rw-r--r--yaksh/templates/manage.html1
-rw-r--r--yaksh/templates/user.html1
-rw-r--r--yaksh/templates/yaksh/login.html1
-rw-r--r--yaksh/templates/yaksh/quizzes_user.html8
-rw-r--r--yaksh/templates/yaksh/user_data.html7
-rw-r--r--yaksh/templates/yaksh/view_answerpaper.html61
-rw-r--r--yaksh/test_models.py12
-rw-r--r--yaksh/test_views.py151
-rw-r--r--yaksh/urls.py1
-rw-r--r--yaksh/views.py12
12 files changed, 251 insertions, 8 deletions
diff --git a/yaksh/models.py b/yaksh/models.py
index acb46f2..81926e6 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -428,6 +428,9 @@ class Quiz(models.Model):
is_trial = models.BooleanField(default=False)
+ view_answerpaper = models.BooleanField('Allow student to view their answer\
+ paper', default=False)
+
objects = QuizManager()
class Meta:
diff --git a/yaksh/templates/base.html b/yaksh/templates/base.html
index 17df0d9..7fe2d27 100644
--- a/yaksh/templates/base.html
+++ b/yaksh/templates/base.html
@@ -16,6 +16,7 @@
<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/base.css">
+ <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/font-awesome.css" type="text/css" />
<style>
body {
diff --git a/yaksh/templates/manage.html b/yaksh/templates/manage.html
index 334f6a2..2fd0f7a 100644
--- a/yaksh/templates/manage.html
+++ b/yaksh/templates/manage.html
@@ -13,6 +13,7 @@
<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/base.css" type="text/css" />
<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/manage.css" type="text/css" />
+ <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/font-awesome.css" type="text/css" />
{% block css %}
{% endblock %}
<script language="JavaScript" type="text/javascript" src="{{ URL_ROOT }}/static/yaksh/js/jquery-1.4.2.min.js"></script>
diff --git a/yaksh/templates/user.html b/yaksh/templates/user.html
index 009dd2f..4805c2d 100644
--- a/yaksh/templates/user.html
+++ b/yaksh/templates/user.html
@@ -15,6 +15,7 @@
{% endblock %}
<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/base.css" type="text/css" />
+ <link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/font-awesome.css" type="text/css" />
{% block css %}
{% endblock %}
diff --git a/yaksh/templates/yaksh/login.html b/yaksh/templates/yaksh/login.html
index 0a78c1b..5694f75 100644
--- a/yaksh/templates/yaksh/login.html
+++ b/yaksh/templates/yaksh/login.html
@@ -6,7 +6,6 @@
{% block css %}
<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/bootstrap-social.css" type="text/css" />
<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/login.css" type="text/css" />
-<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/font-awesome.css" type="text/css" />
{% endblock %}
{% block content %}
diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html
index 6403a21..98c156b 100644
--- a/yaksh/templates/yaksh/quizzes_user.html
+++ b/yaksh/templates/yaksh/quizzes_user.html
@@ -48,6 +48,7 @@
{% endif %}
<table>
<th>Quiz</th>
+ <th>View Answer Paper</th>
<th>Pre requisite quiz</th>
{% for quiz in quizzes %}
{% if quiz.course_id == course.id %}
@@ -63,6 +64,13 @@
</td>
{% endif %}
<td>
+ {% if quiz.view_answerpaper %}
+ <a href="{{ URL_ROOT }}/exam/view_answerpaper/{{ quiz.questionpaper_set.get.id }}/"><i class="fa fa-eye" aria-hidden="true"></i> Can View </a>
+ {% else%}
+ <a><i class="fa fa-eye-slash" aria-hidden="true"></i> Cannot view now </a>
+ {% endif %}
+ </td>
+ <td>
{% if quiz.prerequisite %}
You have to pass {{ quiz.prerequisite.description }} for taking {{ paper.quiz.description }}
{% else %}
diff --git a/yaksh/templates/yaksh/user_data.html b/yaksh/templates/yaksh/user_data.html
index 2e7db50..1060e2d 100644
--- a/yaksh/templates/yaksh/user_data.html
+++ b/yaksh/templates/yaksh/user_data.html
@@ -50,11 +50,12 @@ User IP address: {{ paper.user_ip }}
<h3> Answers </h3>
{% for question, answers in paper.get_question_answers.items %}
<p><strong> Question: {{ question.id }}. {{ question.summary }} (Points: {{ question.points }})</strong> </p>
-{% if question.type == "mcq" %}
-<p> Choices:
-{% for option in question.options.strip.splitlines %} {{option}}, {% endfor %}
+{% if question.type == "mcq" or question.type == "mcc" %}
+<p> Choices:
+{% for testcase in question.get_test_cases %} <br>{{ testcase.options }} {% endfor %}
</p>
<p>Student answer: {{ answers.0 }}</p>
+Autocheck: {{ answers.0.error }}
{% else %}{# non-mcq questions #}
{% for answer in answers %}
{% if not answer.skipped %}
diff --git a/yaksh/templates/yaksh/view_answerpaper.html b/yaksh/templates/yaksh/view_answerpaper.html
new file mode 100644
index 0000000..ae70e69
--- /dev/null
+++ b/yaksh/templates/yaksh/view_answerpaper.html
@@ -0,0 +1,61 @@
+{% extends "user.html" %}
+
+{% block title %} Answer Paper for {{ quiz.description }}{% endblock title %}
+
+{% block manage %}
+
+{% block subtitle %} Answer Paper for {{ quiz.description }}{% endblock %}
+
+
+{% if not data.papers %}
+ <p><b> You have not attempted the quiz {{ quiz.description }} </b></p>
+{% else %}
+ {% for paper in data.papers %}
+ {% if forloop.counter == 2 and data.questionpaperid %}
+ <U><h2> Previous attempts </h2></U>
+ {% endif %}
+ <h2> Quiz: {{ paper.question_paper.quiz.description }} </h2>
+
+ <p>
+ Attempt Number: {{ paper.attempt_number }}<br/>
+ Questions correctly answered: {{ paper.get_answered_str }} <br/>
+ Marks obtained: {{ paper.marks_obtained }} <br/>
+ Start time: {{ paper.start_time }} <br/>
+ </p>
+
+ {% if paper.answers.count %}
+ <h3> Answers </h3>
+ {% for question, answers in paper.get_question_answers.items %}
+ <p><strong> Question: {{ question.id }}. {{ question.summary }} (Mark(s): {{ question.points }})</strong> </p>
+ {% if question.type == "mcq" or question.type == "mcc" %}
+ <p> Choices:
+ {% for testcase in question.get_test_cases %} <br>{{ testcase.options }} {% endfor %}
+ </p>
+ <p>Student answer: {{ answers.0 }}</p>
+ Autocheck: {{ answers.0.error }}
+ {% else %}{# non-mcq questions #}
+ <p>Student answer: </p>
+ {% for answer in answers %}
+ {% if not answer.skipped %}
+ <pre>
+ ###############################################################################
+ {{ answer.answer.strip }}
+ # Autocheck: {{ answer.error }}
+ </pre>
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ {% with answers|last as answer %}
+ <p><em>Obtained Marks: {{answer.marks}} </em> </p>
+ {% endwith %}
+ <hr>
+ {% endfor %} {# for question, answers ... #}
+ <h3>Teacher comments: </h3>
+ {{ paper.comments|default:"None" }}
+ <hr><hr>
+ {% endif %} {# if paper.answers.count #}
+
+ {% endfor %} {# for paper in data.papers #}
+
+{% endif %} {# if not data.papers #}
+{% endblock %}
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index c0721f3..2136987 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -252,6 +252,18 @@ class QuizTestCases(unittest.TestCase):
)
self.assertEqual(trial_quiz.time_between_attempts, 0)
+ def test_view_answerpaper(self):
+ self.assertFalse(self.quiz1.view_answerpaper)
+ self.assertFalse(self.quiz2.view_answerpaper)
+
+ # When
+ self.quiz1.view_answerpaper = True
+ self.quiz1.save()
+
+ # Then
+ self.assertTrue(self.quiz1.view_answerpaper)
+
+
###############################################################################
class QuestionPaperTestCases(unittest.TestCase):
diff --git a/yaksh/test_views.py b/yaksh/test_views.py
index 6e59e26..4dd905e 100644
--- a/yaksh/test_views.py
+++ b/yaksh/test_views.py
@@ -5,6 +5,7 @@ from django.contrib.auth.models import Group
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test import Client
+from django.utils import timezone
from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\
QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\
@@ -632,7 +633,7 @@ class TestRemoveTeacher(TestCase):
target_status_code=301
)
for t_id in teacher_id_list:
- teacher = User.objects.get(id=t_id)
+ teacher = User.objects.get(id=t_id)
self.assertNotIn(teacher, self.course.teachers.all())
@@ -640,7 +641,7 @@ class TestCourses(TestCase):
def setUp(self):
self.client = Client()
- self.mod_group = Group.objects.create(name='moderator')
+ self.mod_group = Group.objects.create(name='moderator')
# Create Moderator with profile
self.user1_plaintext_pass = 'demo1'
@@ -754,7 +755,7 @@ class TestCourseDetail(TestCase):
def setUp(self):
self.client = Client()
- self.mod_group = Group.objects.create(name='moderator')
+ self.mod_group = Group.objects.create(name='moderator')
# Create Moderator with profile
self.user1_plaintext_pass = 'demo1'
@@ -848,7 +849,7 @@ class TestCourseDetail(TestCase):
"""
self.client.login(
username=self.user2.username,
- password=self.user2_plaintext_pass
+ password=self.user2_plaintext_pass
)
response = self.client.get(reverse('yaksh:course_detail',
kwargs={'course_id': self.user1_course.id}
@@ -980,6 +981,148 @@ class TestEnrollRequest(TestCase):
)
self.assertRedirects(response, '/exam/manage/')
+class TestViewAnswerPaper(TestCase):
+ def setUp(self):
+ self.client = Client()
+ self.plaintext_pass = 'demo'
+
+ for i in range(1, 4):
+ User.objects.create_user(
+ username='demo_user{0}'.format(i),
+ password=self.plaintext_pass,
+ first_name='first_name',
+ last_name='last_name',
+ email='demo@test.com'
+ )
+
+ self.user1 = User.objects.get(pk=1)
+
+ self.course = Course.objects.create(name="Python Course",
+ enrollment="Enroll Request",
+ creator=self.user1)
+
+ self.question = Question.objects.create(summary='Dummy', points=1,
+ type='code', user=self.user1)
+
+ self.quiz = Quiz.objects.create(time_between_attempts=0, course=self.course,
+ description='demo quiz', language='Python')
+
+ self.question_paper = QuestionPaper.objects.create(quiz=self.quiz,
+ total_marks=1.0)
+
+ self.question_paper.fixed_questions.add(self.question)
+ self.question_paper.save()
+
+ AnswerPaper.objects.create(user_id=3,
+ attempt_number=1, question_paper=self.question_paper,
+ start_time=timezone.now(), user_ip='101.0.0.1',
+ end_time=timezone.now()+timezone.timedelta(minutes=20))
+
+ def tearDown(self):
+ User.objects.all().delete()
+ Course.objects.all().delete()
+ Question.objects.all().delete()
+ Quiz.objects.all().delete()
+ QuestionPaper.objects.all().delete()
+ AnswerPaper.objects.all().delete()
+
+ def test_anonymous_user(self):
+ # Given, user not logged in
+ redirect_destination = ('/exam/login/?next=/exam'
+ '/view_answerpaper/{0}/'.format(self.question_paper.id))
+
+ # When
+ response = self.client.get(reverse('yaksh:view_answerpaper',
+ kwargs={'questionpaper_id': self.question_paper.id}
+ ),
+ follow=True
+ )
+
+ # Then
+ self.assertRedirects(response, redirect_destination)
+
+ def test_cannot_view(self):
+ # Given, enrolled user tries to view when not permitted by moderator
+ user2 = User.objects.get(pk=2)
+ self.course.students.add(user2)
+ self.course.save()
+ self.quiz.view_answerpaper = False
+ self.quiz.save()
+ self.client.login(
+ username=user2.username,
+ password=self.plaintext_pass
+ )
+
+ # When
+ response = self.client.get(reverse('yaksh:view_answerpaper',
+ kwargs={'questionpaper_id': self.question_paper.id}
+ ),
+ follow=True
+ )
+
+ # Then
+ self.assertRedirects(response, '/exam/quizzes/')
+
+ def test_can_view(self):
+ # Given, user enrolled and can view
+ user3 = User.objects.get(pk=3)
+ self.course.students.add(user3)
+ self.course.save()
+ answerpaper = AnswerPaper.objects.get(pk=1)
+ self.quiz.view_answerpaper = True
+ self.quiz.save()
+ self.client.login(
+ username=user3.username,
+ password=self.plaintext_pass
+ )
+
+ # When
+ response = self.client.get(reverse('yaksh:view_answerpaper',
+ kwargs={'questionpaper_id': self.question_paper.id}
+ ),
+ follow=True
+ )
+
+ # Then
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue('data' in response.context)
+ self.assertTrue('quiz' in response.context)
+ self.assertTemplateUsed(response, 'yaksh/view_answerpaper.html')
+
+
+ # When, wrong question paper id
+ response = self.client.get(reverse('yaksh:view_answerpaper',
+ kwargs={'questionpaper_id': 190}
+ ),
+ follow=True
+ )
+
+ # Then
+ self.assertEqual(response.status_code, 404)
+
+
+ def test_view_when_not_enrolled(self):
+ # Given, user tries to view when not enrolled in the course
+ user2 = User.objects.get(pk=2)
+ self.client.login(
+ username=user2.username,
+ password=self.plaintext_pass
+ )
+ self.course.students.remove(user2)
+ self.course.save()
+ self.quiz.view_answerpaper = True
+ self.quiz.save()
+
+ # When
+ response = self.client.get(reverse('yaksh:view_answerpaper',
+ kwargs={'questionpaper_id': self.question_paper.id}
+ ),
+ follow=True
+ )
+
+ # Then
+ self.assertRedirects(response, '/exam/quizzes/')
+
class TestSelfEnroll(TestCase):
def setUp(self):
diff --git a/yaksh/urls.py b/yaksh/urls.py
index d14ed1d..69d7f87 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -49,6 +49,7 @@ urlpatterns += [
views.skip),
url(r'^enroll_request/(?P<course_id>\d+)/$', views.enroll_request, name='enroll_request'),
url(r'^self_enroll/(?P<course_id>\d+)/$', views.self_enroll, name='self_enroll'),
+ url(r'^view_answerpaper/(?P<questionpaper_id>\d+)/$', views.view_answerpaper, name='view_answerpaper'),
url(r'^manage/$', views.prof_manage, name='manage'),
url(r'^manage/addquestion/$', views.add_question),
url(r'^manage/addquestion/(?P<question_id>\d+)/$', views.edit_question),
diff --git a/yaksh/views.py b/yaksh/views.py
index 923b3c2..1abf248 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -1261,3 +1261,15 @@ def test_quiz(request, mode, quiz_id):
trial_questionpaper = test_mode(current_user, godmode, None, quiz_id)
return my_redirect("/exam/start/{0}".format(trial_questionpaper.id))
+
+
+@login_required
+def view_answerpaper(request, questionpaper_id):
+ user = request.user
+ quiz = get_object_or_404(QuestionPaper, pk=questionpaper_id).quiz
+ if quiz.view_answerpaper and user in quiz.course.students.all():
+ data = AnswerPaper.objects.get_user_data(user, questionpaper_id)
+ context = {'data': data, 'quiz': quiz}
+ return my_render_to_response('yaksh/view_answerpaper.html', context)
+ else:
+ return my_redirect('/exam/quizzes/')