summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yaksh/migrations/0005_auto_20170410_1024.py26
-rw-r--r--yaksh/models.py31
-rw-r--r--yaksh/static/yaksh/js/add_question.js3
-rw-r--r--yaksh/templates/404.html4
-rw-r--r--yaksh/templates/yaksh/course_detail.html4
-rw-r--r--yaksh/templates/yaksh/courses.html2
-rw-r--r--yaksh/templates/yaksh/grade_user.html84
-rw-r--r--yaksh/templates/yaksh/moderator_dashboard.html4
-rw-r--r--yaksh/templates/yaksh/monitor.html67
-rw-r--r--yaksh/templates/yaksh/showquestions.html1
-rw-r--r--yaksh/templates/yaksh/view_answerpaper.html8
-rw-r--r--yaksh/test_models.py73
-rw-r--r--yaksh/urls.py8
-rw-r--r--yaksh/views.py147
14 files changed, 349 insertions, 113 deletions
diff --git a/yaksh/migrations/0005_auto_20170410_1024.py b/yaksh/migrations/0005_auto_20170410_1024.py
new file mode 100644
index 0000000..13b4cce
--- /dev/null
+++ b/yaksh/migrations/0005_auto_20170410_1024.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.5 on 2017-04-10 10:24
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('yaksh', '0004_auto_20170331_0632'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='assignmentupload',
+ name='question_paper',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='yaksh.QuestionPaper'),
+ ),
+ migrations.AlterField(
+ model_name='hooktestcase',
+ name='hook_code',
+ field=models.TextField(default='def check_answer(user_answer):\n \'\'\' Evaluates user answer to return -\n success - Boolean, indicating if code was executed correctly\n mark_fraction - Float, indicating fraction of the\n weight to a test case\n error - String, error message if success is false\n\n In case of assignment upload there will be no user answer \'\'\'\n\n success = False\n err = "Incorrect Answer" # Please make this more specific\n mark_fraction = 0.0\n\n # write your code here\n\n return success, err, mark_fraction\n\n'),
+ ),
+ ]
diff --git a/yaksh/models.py b/yaksh/models.py
index 3e80570..77b5ec4 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -79,7 +79,8 @@ test_status = (
def get_assignment_dir(instance, filename):
return os.sep.join((
- instance.user.username, str(instance.assignmentQuestion.id), filename
+ instance.question_paper.quiz.description, instance.user.username,
+ str(instance.assignmentQuestion.id), filename
))
@@ -1308,11 +1309,35 @@ class AnswerPaper(models.Model):
.format(u.first_name, u.last_name, q.description)
-###############################################################################
+################################################################################
+class AssignmentUploadManager(models.Manager):
+
+ def get_assignments(self, qp, que_id=None, user_id=None):
+ if que_id and user_id:
+ assignment_files = AssignmentUpload.objects.filter(
+ assignmentQuestion_id=que_id, user_id=user_id,
+ question_paper=qp
+ )
+ file_name = User.objects.get(id=user_id).get_full_name()
+ else:
+ assignment_files = AssignmentUpload.objects.filter(
+ question_paper=qp
+ )
+
+ file_name = "{0}_Assignment_files".format(
+ assignment_files[0].question_paper.quiz.description
+ )
+
+ return assignment_files, file_name
+
+
+################################################################################
class AssignmentUpload(models.Model):
user = models.ForeignKey(User)
assignmentQuestion = models.ForeignKey(Question)
assignmentFile = models.FileField(upload_to=get_assignment_dir)
+ question_paper = models.ForeignKey(QuestionPaper, blank=True, null=True)
+ objects = AssignmentUploadManager()
###############################################################################
@@ -1375,7 +1400,9 @@ class HookTestCase(TestCase):
mark_fraction - Float, indicating fraction of the
weight to a test case
error - String, error message if success is false
+
In case of assignment upload there will be no user answer '''
+
success = False
err = "Incorrect Answer" # Please make this more specific
mark_fraction = 0.0
diff --git a/yaksh/static/yaksh/js/add_question.js b/yaksh/static/yaksh/js/add_question.js
index 05752b4..5bec8c6 100644
--- a/yaksh/static/yaksh/js/add_question.js
+++ b/yaksh/static/yaksh/js/add_question.js
@@ -122,9 +122,8 @@ function textareaformat()
});
document.getElementById('my').innerHTML = document.getElementById('id_description').value ;
-
if (document.getElementById('id_grade_assignment_upload').checked ||
- document.getElementById('id_type').val() == 'upload'){
+ document.getElementById('id_type').value == 'upload'){
$("#id_grade_assignment_upload").prop("disabled", false);
}
else{
diff --git a/yaksh/templates/404.html b/yaksh/templates/404.html
index 7d33dd3..e9d99de 100644
--- a/yaksh/templates/404.html
+++ b/yaksh/templates/404.html
@@ -1,5 +1,7 @@
{% extends "base.html" %}
{% block content %}
-The requested page does not exist.
+It seems that you have encountered an error
+Type of Error - {{ exception }}
+Please contact your administrator
{% endblock %}
diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html
index 4b7efaf..81569fa 100644
--- a/yaksh/templates/yaksh/course_detail.html
+++ b/yaksh/templates/yaksh/course_detail.html
@@ -1,8 +1,8 @@
{% extends "manage.html" %}
-{% block title %} Course {% endblock title %}
+{% block title %} Course Details {% endblock title %}
-{% block subtitle %} {{ course.name }} {% endblock %}
+{% block pagetitle %} Course Details for {{ course.name|title }} {% endblock %}
{% block script %}
<script language="JavaScript" type="text/javascript" src="{{ URL_ROOT }}/static/yaksh/js/course.js"></script>
diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html
index 60e6bf4..e09a9cc 100644
--- a/yaksh/templates/yaksh/courses.html
+++ b/yaksh/templates/yaksh/courses.html
@@ -1,5 +1,5 @@
{% extends "manage.html" %}
-
+{% block title %} Courses {% endblock %}
{% block pagetitle %} Courses {% endblock pagetitle %}
{% block content %}
{% if not courses %}
diff --git a/yaksh/templates/yaksh/grade_user.html b/yaksh/templates/yaksh/grade_user.html
index 1cb1f99..c93ec10 100644
--- a/yaksh/templates/yaksh/grade_user.html
+++ b/yaksh/templates/yaksh/grade_user.html
@@ -1,5 +1,7 @@
{% extends "manage.html" %}
+{% block title %} Grade User {% endblock %}
+
{% block pagetitle %} Grade User {% endblock pagetitle %}
{% block content %}
@@ -8,11 +10,10 @@
<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML"></script>
{% endblock script %}
-
{% if course_details %}
<table id="course-details" class="table table-bordered">
<tr>
- <th>Courses</th>
+ <th>Courses</th>
<th> Quizzes </th>
</tr>
@@ -37,23 +38,31 @@
{% endif %}
<div class="row">
-{%if users %}
+{% if not course_details %}
+{% if users %}
<div id = "student" class="col-md-2">
{% 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>
+{% else %}
+<h4>No Users Found for {{ quiz.description }}</h4>
+{% endif %}
{% endif %}
+{% if has_quiz_assignments %}
+<a href="{{URL_ROOT}}/exam/manage/download/quiz_assignments/{{quiz_id}}/">
+ Download All Assignments</a>
+{% endif %}
<div id = "paper" class="col-md-10">
{% 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 }}
+<p><b>Name:</b> {{ data.user.get_full_name.title }}
{% if data.profile %}
<p><b> Roll number:</b> {{ data.profile.roll_number }}
@@ -68,7 +77,8 @@
<hr>
{{ paper.total_marks }}
-<h3> Quiz: {{ paper.question_paper.quiz.description }} </h3>
+<h4> Course: {{ paper.question_paper.quiz.course.name }}</h4>
+<h4> Quiz: {{ paper.question_paper.quiz.description }} </h4>
<p>
Attempt Number: <b>{{paper.attempt_number}} </b>
@@ -80,7 +90,6 @@ Attempt Number: <b>{{paper.attempt_number}} </b>
</option>
{% endfor %}
</select>
-
<br/>Questions correctly answered: {{ paper.get_answered_str }} <br/>
Total attempts at questions: {{ paper.answers.count }} <br/>
Marks obtained: {{ paper.marks_obtained }} <br/>
@@ -95,7 +104,6 @@ Status : <b style="color: red;"> Failed </b><br/>
Status : <b style="color: green;"> Passed </b><br/>
{% endif %}
</p>
-
{% if paper.answers.count %}
<h4> Report </h4><br>
@@ -122,8 +130,8 @@ Status : <b style="color: green;"> Passed </b><br/>
{% endif %}
method="post">
{% csrf_token %}
-{% for question, answers in paper.get_question_answers.items %}
+{% for question, answers in paper.get_question_answers.items %}
<div class="panel panel-info">
<div class="panel-heading">
<strong> Details: {{forloop.counter}}. {{ question.summary }}
@@ -153,7 +161,6 @@ Status : <b style="color: green;"> Passed </b><br/>
<strong>{{ testcase.error_margin|safe }}</strong>
{% endif %}
{% endfor %}
-
{% else %}
<h5> <u>Test cases: </u></h5>
{% for testcase in question.get_test_cases %}
@@ -163,29 +170,50 @@ Status : <b style="color: green;"> Passed </b><br/>
</div>
</div>
<h5>Student answer: </h5>
- {% for ans in answers %}
- {% if ans.answer.correct %}
- <div class="panel panel-success">
- <div class="panel-heading">Correct answer:
+ {% if question.type == "upload" %}
+ {% if has_user_assignments %}
+ <a href="{{URL_ROOT}}/exam/manage/download/user_assignment/{{question.id}}/{{data.user.id}}/{{paper.question_paper.quiz.id}}">
+ <div class="panel">
+ Assignment File for {{ data.user.get_full_name.title }}
+ </div>
+ </a>
+ {% with answers|last as answer%}
+ {% if answer.answer.correct %}
+ <div class="panel panel-success">
+ <div class="panel-heading">Correct answer</div></div>
+ {% else %}
+ <div class="panel panel-danger">
+ <div class="panel-heading">Incorrect Answer</div></div>
+ {% endif %}
+ {% endwith %}
+ {% else %}
+ <h5>No Assignment submitted by {{ data.user.get_full_name.title }}</h5>
+ {% endif %}
+ {% else %}
+ {% for ans in answers %}
+ {% if ans.answer.correct %}
+ <div class="panel panel-success">
+ <div class="panel-heading">Correct answer:
+ {% else %}
+ <div class="panel panel-danger">
+ <div class="panel-heading">Error:
+ {% endif %}
+ {% for err in ans.error_list %}
+ <div><pre>{{ err }}</pre></div>
+ {% endfor %}
+ </div>
+ <div class="panel-body">
+ {% if question.type != "code" %}
+ <div class="well well-sm">
+ {{ ans.answer.answer.strip|safe }}
+ </div>
{% else %}
- <div class="panel panel-danger">
- <div class="panel-heading">Error:
+ <pre><code>{{ ans.answer.answer.strip|safe }}</code></pre>
{% endif %}
- {% for err in ans.error_list %}
- <div><pre>{{ err }}</pre></div>
+ </div>
+ </div>
{% endfor %}
- </div>
- <div class="panel-body">
- {% if question.type != "code" %}
- <div class="well well-sm">
- {{ ans.answer.answer.strip|safe }}
- </div>
- {% else %}
- <pre><code>{{ ans.answer.answer.strip|safe }}</code></pre>
{% endif %}
- </div>
- </div>
- {% endfor %}
{% with answers|last as answer %}
Marks: <input id="q{{ question.id }}" type="text"
name="q{{ question.id }}_marks" size="4"
diff --git a/yaksh/templates/yaksh/moderator_dashboard.html b/yaksh/templates/yaksh/moderator_dashboard.html
index 0468ed9..faccffe 100644
--- a/yaksh/templates/yaksh/moderator_dashboard.html
+++ b/yaksh/templates/yaksh/moderator_dashboard.html
@@ -9,6 +9,7 @@
<center><h4>List of quizzes! Click on the given links to have a look at answer papers for a quiz.</h4></center>
<table class="table table-bordered">
+ <th>Course</th>
<th>Quiz</th>
<th>Taken By</th>
<th>No. of users Passed</th>
@@ -16,6 +17,9 @@
{% for paper, answer_papers, users_passed, users_failed in users_per_paper %}
<tr>
<td>
+ {{ paper.quiz.course.name }}
+ </td>
+ <td>
<a href="{{URL_ROOT}}/exam/manage/monitor/{{paper.id}}/">{{ paper.quiz.description }}</a>
</td>
<td>
diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html
index d2c89ce..9ce0dc4 100644
--- a/yaksh/templates/yaksh/monitor.html
+++ b/yaksh/templates/yaksh/monitor.html
@@ -1,15 +1,16 @@
{% extends "manage.html" %}
{% load custom_filters %}
-
-{% block pagetitle %} Quiz results {% endblock pagetitle %}
+{% block title %} Monitor {% endblock %}
+{% block pagetitle %} {{ msg }} {% endblock pagetitle %}
{% block meta %} <meta http-equiv="refresh" content="30"/> {% endblock meta %}
{% block script %}
+{% if papers %}
<script src="{{ URL_ROOT }}/static/yaksh/js/jquery.tablesorter.min.js"></script>
<script type="text/javascript">
-$(document).ready(function()
+$(document).ready(function()
{
$("#result-table").tablesorter({sortList: [[5,1]]});
var papers_length = "{{papers|length}}";
@@ -23,41 +24,48 @@ $(document).ready(function()
}
});
</script>
-
+{% endif %}
{% endblock %}
-
-{% block subtitle %}
- {% if not quizzes and not quiz %}
- Quiz Results
- {% endif %}
- {% if quizzes %}
- Available Quizzes
- {% endif %}
- {% if quiz %}
- {{ quiz.description }} Results
- {% endif %}
-{% endblock %}
{% block content %}
- {% if not quizzes and not quiz %}
- <center><h5> No quizzes available. </h5></center>
- {% endif %}
{# ############################################################### #}
{# This is rendered when we are just viewing exam/monitor #}
-{% if quizzes %}
-<ul class="list-group">
-{% for q in quizzes %}
-<li class="list-group-item"><a href="{{URL_ROOT}}/exam/manage/monitor/{{q.id}}/">{{ q.quiz.description }}</a></li>
-{% endfor %}
-</ul>
+
+{% if course_details %}
+ <table id="course-details" class="table table-bordered">
+ <tr>
+ <th>Courses</th>
+ <th> Quizzes </th>
+ </tr>
+
+ {% for course in course_details %}
+ <tr>
+ <td><ul class="list-group">{{course.name}} </td>
+
+ {% if course.get_quizzes %}
+ <td>
+ {% for quiz in course.get_quizzes %}
+ <li class="list-group-item"><a href = "{{URL_ROOT}}/exam/manage/monitor/{{quiz.id}}">
+ {{quiz.description}}
+ </a></li>
+ {% endfor %}
+ </td>
+ {% else %}
+ <td> No quiz</td>
+ {% endif %}
+ </ul></tr>
+ {% endfor %}
+ </table>
{% endif %}
{# ############################################################### #}
{# This is rendered when we are just viewing exam/monitor/quiz_num #}
+{% if msg != "Monitor" %}
{% if quiz %}
-
{% if papers %}
+<p>Course Name: {{ quiz.course.name }}</p>
+<p>Quiz Name: {{ quiz.description }}</p>
<p>Number of papers: {{ papers|length }} </p>
{% completed papers as completed_papers %}
{# template tag used to get the count of completed papers #}
@@ -80,6 +88,7 @@ $(document).ready(function()
<th> Marks obtained </th>
<th> Attempts </th>
<th> Time Remaining </th>
+ <th> Status </th>
</tr>
</thead>
<tbody>
@@ -93,13 +102,17 @@ $(document).ready(function()
<td> {{ paper.marks_obtained }} </td>
<td> {{ paper.answers.count }} </td>
<td id="time_left{{forloop.counter0}}"> {{ paper.time_left }} </td>
+ <td>{{ paper.status }}</td>
</div>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
-<p> No answer papers so far. </p>
+<p> No answer papers found for {{ quiz.description }}</p>
{% endif %} {# if papers #}
+{% else %}
+<h4>No Quiz Found</h4>
+{% endif %}
{% endif %}
{% endblock %}
diff --git a/yaksh/templates/yaksh/showquestions.html b/yaksh/templates/yaksh/showquestions.html
index 157b378..a136ddf 100644
--- a/yaksh/templates/yaksh/showquestions.html
+++ b/yaksh/templates/yaksh/showquestions.html
@@ -1,5 +1,6 @@
{% extends "manage.html" %}
+{% block title %} Questions {% endblock %}
{% block pagetitle %} List of Questions {% endblock pagetitle %}
diff --git a/yaksh/templates/yaksh/view_answerpaper.html b/yaksh/templates/yaksh/view_answerpaper.html
index 4520ac3..f4c8846 100644
--- a/yaksh/templates/yaksh/view_answerpaper.html
+++ b/yaksh/templates/yaksh/view_answerpaper.html
@@ -84,7 +84,13 @@
<h5><u>Student answer:</u></h5>
<div class="well well-sm">
{{ answers.0.answer|safe }}
- </div>
+ {% if question.type == "upload" and has_user_assignment %}
+ <a href="{{URL_ROOT}}/exam/download/user_assignment/{{question.id}}/{{data.user.id}}/{{paper.question_paper.quiz.id}}">
+ <div class="panel">
+ Assignment File for {{ data.user.get_full_name.title }}
+ </div></a>
+ {% endif %}
+ </div>
</div>
</div>
{% else %}
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index dbd367b..9bd8492 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -1,7 +1,7 @@
import unittest
from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\
QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\
- StdIOBasedTestCase, FileUpload, McqTestCase
+ StdIOBasedTestCase, FileUpload, McqTestCase, AssignmentUpload
import json
from datetime import datetime, timedelta
from django.utils import timezone
@@ -68,12 +68,7 @@ def tearDownModule():
Quiz.objects.all().delete()
Course.objects.all().delete()
QuestionPaper.objects.all().delete()
-
- que_id_list = ["25", "22", "24", "27"]
- for que_id in que_id_list:
- dir_path = os.path.join(os.getcwd(), "yaksh", "data","question_{0}".format(que_id))
- if os.path.exists(dir_path):
- shutil.rmtree(dir_path)
+
###############################################################################
class ProfileTestCases(unittest.TestCase):
@@ -1034,3 +1029,67 @@ class TestCaseTestCases(unittest.TestCase):
exp_data = json.loads(self.answer_data_json)
self.assertEqual(actual_data['metadata']['user_answer'], exp_data['metadata']['user_answer'])
self.assertEqual(actual_data['test_case_data'], exp_data['test_case_data'])
+
+
+class AssignmentUploadTestCases(unittest.TestCase):
+ def setUp(self):
+ self.user1 = User.objects.get(username="demo_user")
+ self.user1.first_name = "demo"
+ self.user1.last_name = "user"
+ self.user1.save()
+ self.user2 = User.objects.get(username="demo_user3")
+ self.user2.first_name = "demo"
+ self.user2.last_name = "user3"
+ self.user2.save()
+ self.quiz = Quiz.objects.get(description="demo quiz 1")
+
+ self.questionpaper = QuestionPaper.objects.create(quiz=self.quiz,
+ total_marks=0.0,
+ shuffle_questions=True
+ )
+ self.question = Question.objects.create(summary='Assignment',
+ language='Python',
+ type='upload',
+ active=True,
+ description='Upload a file',
+ points=1.0,
+ snippet='',
+ user=self.user1
+ )
+ self.questionpaper.fixed_question_order = "{0}".format(self.question.id)
+ self.questionpaper.fixed_questions.add(self.question)
+ file_path1 = os.path.join(tempfile.gettempdir(), "upload1.txt")
+ file_path2 = os.path.join(tempfile.gettempdir(), "upload2.txt")
+ self.assignment1 = AssignmentUpload.objects.create(user=self.user1,
+ assignmentQuestion=self.question, assignmentFile=file_path1,
+ question_paper=self.questionpaper
+ )
+ self.assignment2 = AssignmentUpload.objects.create(user=self.user2,
+ assignmentQuestion=self.question, assignmentFile=file_path2,
+ question_paper=self.questionpaper
+ )
+
+ def test_get_assignments_for_user_files(self):
+ assignment_files, file_name = AssignmentUpload.objects.get_assignments(
+ self.questionpaper, self.question.id,
+ self.user1.id
+ )
+ self.assertIn("upload1.txt", assignment_files[0].assignmentFile.name)
+ self.assertEqual(assignment_files[0].user, self.user1)
+ actual_file_name = self.user1.get_full_name().replace(" ", "_")
+ file_name = file_name.replace(" ", "_")
+ self.assertEqual(file_name, actual_file_name)
+
+ def test_get_assignments_for_quiz_files(self):
+ assignment_files, file_name = AssignmentUpload.objects.get_assignments(
+ self.questionpaper
+ )
+ files = [os.path.basename(file.assignmentFile.name)
+ for file in assignment_files]
+ question_papers = [file.question_paper for file in assignment_files]
+ self.assertIn("upload1.txt", files)
+ self.assertIn("upload2.txt", files)
+ self.assertEqual(question_papers[0].quiz, self.questionpaper.quiz)
+ actual_file_name = self.quiz.description.replace(" ", "_")
+ file_name = file_name.replace(" ", "_")
+ self.assertIn(actual_file_name, file_name)
diff --git a/yaksh/urls.py b/yaksh/urls.py
index 03e5354..fae8204 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -28,6 +28,8 @@ urlpatterns = [
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'^download/user_assignment/(?P<question_id>\d+)/(?P<user_id>\d+)/(?P<quiz_id>\d+)$',
+ views.download_assignment_file, name="download_user_assignment"),
url(r'^manage/$', views.prof_manage, name='manage'),
url(r'^manage/addquestion/$', views.add_question),
url(r'^manage/addquestion/(?P<question_id>\d+)/$', views.add_question),
@@ -42,7 +44,7 @@ urlpatterns = [
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/monitor/(?P<quiz_id>\d+)/$', views.monitor),
url(r'^manage/user_data/(?P<user_id>\d+)/(?P<questionpaper_id>\d+)/$',
views.user_data),
url(r'^manage/user_data/(?P<user_id>\d+)/$', views.user_data),
@@ -93,4 +95,8 @@ urlpatterns = [
url(r'^manage/create_demo_course/$', views.create_demo_course),
url(r'^manage/courses/download_course_csv/(?P<course_id>\d+)/$',
views.download_course_csv),
+ url(r'^manage/download/user_assignment/(?P<question_id>\d+)/(?P<user_id>\d+)/(?P<quiz_id>\d+)/$',
+ views.download_assignment_file),
+ url(r'^manage/download/quiz_assignments/(?P<quiz_id>\d+)/$',
+ views.download_assignment_file)
]
diff --git a/yaksh/views.py b/yaksh/views.py
index aa23d01..fa72008 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -24,6 +24,11 @@ from itertools import chain
import json
import six
from textwrap import dedent
+import zipfile
+try:
+ from StringIO import StringIO as string_io
+except ImportError:
+ from io import BytesIO as string_io
# Local imports.
from yaksh.models import get_model_class, Quiz, Question, QuestionPaper, QuestionSet, Course
from yaksh.models import Profile, Answer, AnswerPaper, User, TestCase, FileUpload,\
@@ -292,9 +297,11 @@ def prof_manage(request, msg=None):
user = request.user
ci = RequestContext(request)
if user.is_authenticated() and is_moderator(user):
- question_papers = QuestionPaper.objects.filter(quiz__course__creator=user,
- quiz__is_trial=False
- )
+ question_papers = QuestionPaper.objects.filter(
+ Q(quiz__course__creator=user) |
+ Q(quiz__course__teachers=user),
+ quiz__is_trial=False
+ ).distinct()
trial_paper = AnswerPaper.objects.filter(user=user,
question_paper__quiz__is_trial=True
)
@@ -510,22 +517,33 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
elif current_question.type == 'upload':
# if time-up at upload question then the form is submitted without
# validation
- if 'assignment' in request.FILES:
- assignment_filename = request.FILES.getlist('assignment')
+ assignment_filename = request.FILES.getlist('assignment')
+ if not assignment_filename:
+ msg = "Please upload assignment file"
+ return show_question(request, current_question, paper, notification=msg)
+
for fname in assignment_filename:
- if AssignmentUpload.objects.filter(
- assignmentQuestion=current_question,
- assignmentFile__icontains=fname, user=user).exists():
- assign_file = AssignmentUpload.objects.get(
- assignmentQuestion=current_question,
- assignmentFile__icontains=fname, user=user)
+ assignment_files = AssignmentUpload.objects.filter(
+ assignmentQuestion=current_question,
+ assignmentFile__icontains=fname, user=user,
+ question_paper=questionpaper_id)
+ if assignment_files.exists():
+ assign_file = assignment_files.get(
+ assignmentQuestion=current_question,
+ assignmentFile__icontains=fname, user=user,
+ question_paper=questionpaper_id)
os.remove(assign_file.assignmentFile.path)
assign_file.delete()
AssignmentUpload.objects.create(user=user,
- assignmentQuestion=current_question, assignmentFile=fname
+ assignmentQuestion=current_question, assignmentFile=fname,
+ question_paper_id=questionpaper_id
)
user_answer = 'ASSIGNMENT UPLOADED'
if not current_question.grade_assignment_upload:
+ new_answer = Answer(question=current_question, answer=user_answer,
+ correct=False, error=json.dumps([]))
+ new_answer.save()
+ paper.answers.add(new_answer)
next_q = paper.add_completed_question(current_question.id)
return show_question(request, next_q, paper)
else:
@@ -792,7 +810,7 @@ def show_statistics(request, questionpaper_id, attempt_number=None):
@login_required
-def monitor(request, questionpaper_id=None):
+def monitor(request, quiz_id=None):
"""Monitor the progress of the papers taken so far."""
user = request.user
@@ -800,22 +818,23 @@ def monitor(request, questionpaper_id=None):
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:
- q_paper = QuestionPaper.objects.filter(Q(quiz__course__creator=user) |
- Q(quiz__course__teachers=user),
- quiz__is_trial=False
- ).distinct()
- context = {'papers': [],
- 'quiz': None,
- 'quizzes': q_paper}
+ if quiz_id is None:
+ course_details = Course.objects.filter(Q(creator=user) |
+ Q(teachers=user),
+ is_trial=False).distinct()
+ context = {'papers': [], "course_details": course_details,
+ "msg": "Monitor"}
return my_render_to_response('yaksh/monitor.html', context,
context_instance=ci)
# quiz_id is not None.
try:
+ quiz = get_object_or_404(Quiz, id=quiz_id)
+ if not quiz.course.is_creator(user) and not quiz.course.is_teacher(user):
+ raise Http404('This course does not belong to you')
q_paper = QuestionPaper.objects.filter(Q(quiz__course__creator=user) |
Q(quiz__course__teachers=user),
quiz__is_trial=False,
- id=questionpaper_id).distinct()
+ quiz_id=quiz_id).distinct()
except QuestionPaper.DoesNotExist:
papers = []
q_paper = None
@@ -830,8 +849,8 @@ def monitor(request, questionpaper_id=None):
last_attempt_num=Max('attempt_number'))
latest_attempts.append(papers.get(user__in=auser,
attempt_number=last_attempt['last_attempt_num']))
- context = {'papers': papers, 'quiz': q_paper, 'quizzes': None,
- 'latest_attempts': latest_attempts,}
+ context = {'papers': papers, "quiz": quiz, "msg": "Quiz Results",
+ 'latest_attempts': latest_attempts}
return my_render_to_response('yaksh/monitor.html', context,
context_instance=ci)
@@ -928,14 +947,15 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None):
if 'remove-fixed' in request.POST:
question_ids = request.POST.getlist('added-questions', None)
- que_order = question_paper.fixed_question_order.split(",")
- for qid in question_ids:
- que_order.remove(qid)
- if que_order:
- question_paper.fixed_question_order = ",".join(que_order)
- else:
- question_paper.fixed_question_order = ""
- question_paper.save()
+ if question_paper.fixed_question_order:
+ que_order = question_paper.fixed_question_order.split(",")
+ for qid in question_ids:
+ que_order.remove(qid)
+ if que_order:
+ question_paper.fixed_question_order = ",".join(que_order)
+ else:
+ question_paper.fixed_question_order = ""
+ question_paper.save()
question_paper.fixed_questions.remove(*question_ids)
if 'add-random' in request.POST:
@@ -1117,7 +1137,17 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
.values("id")
user_details = AnswerPaper.objects\
.get_users_for_questionpaper(questionpaper_id)
- context = {"users": user_details, "quiz_id": quiz_id}
+ quiz = get_object_or_404(Quiz, id=quiz_id)
+ if not quiz.course.is_creator(current_user) and not \
+ quiz.course.is_teacher(current_user):
+ raise Http404('This course does not belong to you')
+
+ has_quiz_assignments = AssignmentUpload.objects.filter(
+ question_paper_id=questionpaper_id
+ ).exists()
+ context = {"users": user_details, "quiz_id": quiz_id, "quiz":quiz,
+ "has_quiz_assignments": has_quiz_assignments
+ }
if user_id is not None:
attempts = AnswerPaper.objects.get_user_all_attempts\
@@ -1127,23 +1157,27 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
attempt_number = attempts[0].attempt_number
except IndexError:
raise Http404('No attempts for paper')
-
+ has_user_assignments = AssignmentUpload.objects.filter(
+ question_paper_id=questionpaper_id,
+ user_id=user_id
+ ).exists()
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
+ "attempts": attempts, "user_id": user_id,
+ "has_user_assignments": has_user_assignments,
+ "has_quiz_assignments": has_quiz_assignments
}
if request.method == "POST":
papers = data['papers']
for paper in papers:
- for question, answers, errors in six.iteritems(paper.get_question_answers()):
+ for question, answers in six.iteritems(paper.get_question_answers()):
marks = float(request.POST.get('q%d_marks' % question.id, 0))
- answers = answers[-1]
- answers.set_marks(marks)
- answers.save()
+ answer = answers[-1]['answer']
+ answer.set_marks(marks)
+ answer.save()
paper.update_marks()
paper.comments = request.POST.get(
'comments_%d' % paper.question_paper.id, 'No comments')
@@ -1324,7 +1358,10 @@ def view_answerpaper(request, questionpaper_id):
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}
+ has_user_assignment = AssignmentUpload.objects.filter(user=user,
+ question_paper_id=questionpaper_id).exists()
+ context = {'data': data, 'quiz': quiz,
+ "has_user_assignment":has_user_assignment}
return my_render_to_response('yaksh/view_answerpaper.html', context)
else:
return my_redirect('/exam/quizzes/')
@@ -1463,3 +1500,31 @@ def new_activation(request):
return my_render_to_response('yaksh/activation_status.html', context,
context_instance=ci)
+
+@login_required
+def download_assignment_file(request, quiz_id, question_id=None, user_id=None):
+ user = request.user
+ qp = QuestionPaper.objects.get(quiz_id=quiz_id)
+ assignment_files, file_name = AssignmentUpload.objects.get_assignments(qp,
+ question_id,
+ user_id
+ )
+ zipfile_name = string_io()
+ zip_file = zipfile.ZipFile(zipfile_name, "w")
+ for f_name in assignment_files:
+ folder = f_name.user.get_full_name().replace(" ", "_")
+ sub_folder = f_name.assignmentQuestion.summary.replace(" ", "_")
+ folder_name = os.sep.join((folder, sub_folder, os.path.basename(
+ f_name.assignmentFile.name))
+ )
+ zip_file.write(f_name.assignmentFile.path, folder_name
+ )
+ zip_file.close()
+ zipfile_name.seek(0)
+ response = HttpResponse(content_type='application/zip')
+ response['Content-Disposition'] = '''attachment;\
+ filename={0}.zip'''.format(
+ file_name.replace(" ", "_")
+ )
+ response.write(zipfile_name.read())
+ return response