summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh')
-rw-r--r--yaksh/models.py20
-rw-r--r--yaksh/static/yaksh/js/show_question.js12
-rw-r--r--yaksh/templates/yaksh/quizzes_user.html11
-rw-r--r--yaksh/templates/yaksh/showquestions.html53
-rw-r--r--yaksh/views.py568
5 files changed, 430 insertions, 234 deletions
diff --git a/yaksh/models.py b/yaksh/models.py
index 56cced8..063e1e3 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -855,13 +855,12 @@ class QuestionPaper(models.Model):
def make_answerpaper(self, user, ip, attempt_num):
"""Creates an answer paper for the user to attempt the quiz"""
- ans_paper = AnswerPaper.objects.filter(user=user,
- attempt_number=attempt_num,
- question_paper=self
- ).order_by('-id')
- if ans_paper:
- ans_paper = ans_paper[0]
- else:
+ try:
+ ans_paper = AnswerPaper.objects.get(user=user,
+ attempt_number=attempt_num,
+ question_paper=self
+ )
+ except AnswerPaper.DoesNotExist:
ans_paper = AnswerPaper(
user=user,
user_ip=ip,
@@ -877,6 +876,13 @@ class QuestionPaper(models.Model):
ans_paper.questions.add(question)
for question in questions:
ans_paper.questions_unanswered.add(question)
+ except AnswerPaper.MultipleObjectsReturned:
+ ans_paper = AnswerPaper.objects.get(user=user,
+ attempt_number=attempt_num,
+ question_paper=self
+ ).order_by('-id')
+ ans_paper = ans_paper[0]
+
return ans_paper
def _is_questionpaper_passed(self, user):
diff --git a/yaksh/static/yaksh/js/show_question.js b/yaksh/static/yaksh/js/show_question.js
index e7cd817..e6825a0 100644
--- a/yaksh/static/yaksh/js/show_question.js
+++ b/yaksh/static/yaksh/js/show_question.js
@@ -37,7 +37,17 @@ function confirm_edit(frm)
else
return true;
}
+
+function append_tag(tag){
+ var tag_name = document.getElementById("question_tags");
+ if (tag_name.value != null){
+ tag_name.value = tag.value+", "+tag_name.value;
+ }
+ else{
+ tag_name.value = tag.value;
+ }
+}
$(document).ready(function()
{
$("#questions-table").tablesorter({sortList: [[0,0], [4,0]]});
- }); \ No newline at end of file
+ });
diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html
index 90d7f8e..b90db18 100644
--- a/yaksh/templates/yaksh/quizzes_user.html
+++ b/yaksh/templates/yaksh/quizzes_user.html
@@ -28,8 +28,9 @@ No Courses to display
<div class="col-md-4">
<h4><b><u> {{ course.name }} by {{ course.creator.get_full_name }}</u></b></h4>
</div>
- <div class="col-md-4">
- {% if course.hidden %}<span class="label label-info">Open Course</span>
+ <div class="col-md-4">
+ {% if not course.active %}
+ <span class="label label-danger">Closed</span>
{% endif %}
{% if user in course.requests.all %} <span class="label label-warning">Request Pending </span>
{% elif user in course.rejected.all %}<span class="label label-danger">Request Rejected</span>
@@ -45,8 +46,8 @@ No Courses to display
<span class="label label-danger">Enrollment Closed</span>
{% endif %}
{% endif %}
- </div>
- </div>
+ </div>
+ </div>
<div class="row">
{% if user in course.students.all %}
@@ -57,7 +58,7 @@ No Courses to display
{% for quiz in course.get_quizzes %}
{% if quiz.active and quiz.course_id == course.id %}
<tr>
- {% if not quiz.is_expired %}
+ {% if not quiz.is_expired and course.active %}
<td>
<a href="{{ URL_ROOT }}/exam/start/{{quiz.questionpaper_set.get.id}}">{{ quiz.description }}</a><br>
</td>
diff --git a/yaksh/templates/yaksh/showquestions.html b/yaksh/templates/yaksh/showquestions.html
index 78be301..a8983bd 100644
--- a/yaksh/templates/yaksh/showquestions.html
+++ b/yaksh/templates/yaksh/showquestions.html
@@ -58,8 +58,11 @@ Upload File <span class="glyphicon glyphicon-open"/></button>
{{ msg }}
</div>
{% endif %}
+<br><br>
+<form name=frm action="" method="post">
+<!-- Filtering Questions -->
<div class="row" id="selectors">
- <h5 style="padding-left: 20px;">Filters</h5>
+ <h4 style="padding-left: 20px;">Filters Questions: </h4>
<div class="col-md-3">
{{ form.question_type }}
</div>
@@ -69,10 +72,40 @@ Upload File <span class="glyphicon glyphicon-open"/></button>
<div class="col-md-3">
{{ form.marks }}
</div>
-</div>
-<br>
- <button class="btn btn-primary" type="button" onClick='location.replace("{{URL_ROOT}}");'>Clear Filters</button>
<br>
+<h4 style="padding-left: 20px;">Or</h4>
+
+<h4 style="padding-left: 20px;">Search using Tags: </h4>
+</div>
+<!-- Searching Tags -->
+{% csrf_token %}
+ <div class="col-md-14">
+ <div class="input-group">
+ <span class="input-group-addon" id="basic-addon1">Search Questions </span>
+ <input type="text" id="question_tags" name="question_tags" class="form-control"
+ placeholder="Search using comma separated Tags">
+ <span class="input-group-btn">
+ <button class="btn btn-default" type="submit">Search</button>
+ </span>
+ <div class="col-md-6">
+ <select class="form-control" id="sel1" onchange="append_tag(this);">
+ {% if all_tags %}
+ <option value="" disabled selected>Available Tags</option>
+ {% for tag in all_tags %}
+ <option>
+ {{tag}}
+ </option>
+ {% endfor %}
+ {% else %}
+ <option value="" disabled selected>No Available Tags</option>
+ {% endif %}
+ </select>
+ </div>
+ </div>
+ </div>
+<br><br>
+<button class="btn btn-primary" type="button" onClick='location.replace("{{URL_ROOT}}");'>
+ Clear Filters</button>
<div id="filtered-questions">
{% if questions %}
@@ -90,15 +123,15 @@ Upload File <span class="glyphicon glyphicon-open"/></button>
</thead>
<tbody>
-{% for i in questions %}
+{% for question in questions %}
<tr>
<td>
-<input type="checkbox" name="question" value="{{ i.id }}">
+<input type="checkbox" name="question" value="{{ question.id }}">
</td>
-<td><a href="{{URL_ROOT}}/exam/manage/addquestion/{{ i.id }}">{{i.summary|capfirst}}</a></td>
-<td>{{i.language|capfirst}}</td>
-<td>{{i.type|capfirst}}</td>
-<td>{{i.points}}</td>
+<td><a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}">{{question.summary|capfirst}}</a></td>
+<td>{{question.language|capfirst}}</td>
+<td>{{question.type|capfirst}}</td>
+<td>{{question.points}}</td>
</tr>
{% endfor %}
</tbody>
diff --git a/yaksh/views.py b/yaksh/views.py
index add791e..7898d57 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -29,16 +29,20 @@ try:
from StringIO import StringIO as string_io
except ImportError:
from io import BytesIO as string_io
+import re
# Local imports.
-from yaksh.models import get_model_class, Quiz, Question, QuestionPaper, QuestionSet, Course
-from yaksh.models import Profile, Answer, AnswerPaper, User, TestCase, FileUpload,\
- StandardTestCase, McqTestCase,\
- StdIOBasedTestCase, HookTestCase, IntegerTestCase,\
- FloatTestCase, StringTestCase
-from yaksh.forms import UserRegisterForm, UserLoginForm, QuizForm,\
- QuestionForm, RandomQuestionForm,\
- QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm,\
- get_object_form, FileForm, QuestionPaperForm
+from yaksh.models import (
+ Answer, AnswerPaper, AssignmentUpload, Course, FileUpload, FloatTestCase,
+ HookTestCase, IntegerTestCase, McqTestCase, Profile,
+ QuestionPaper, QuestionSet, Quiz, Question, StandardTestCase,
+ StdIOBasedTestCase, StringTestCase, TestCase, User,
+ get_model_class
+)
+from yaksh.forms import (
+ UserRegisterForm, UserLoginForm, QuizForm, QuestionForm,
+ RandomQuestionForm, QuestionFilterForm, CourseForm, ProfileForm,
+ UploadFileForm, get_object_form, FileForm, QuestionPaperForm
+)
from .settings import URL_ROOT
from yaksh.models import AssignmentUpload
from .file_utils import extract_files
@@ -75,6 +79,7 @@ def add_to_group(users):
if not is_moderator(user):
user.groups.add(group)
+
@email_verified
def index(request, next_url=None):
"""The start page.
@@ -107,16 +112,18 @@ def user_register(request):
if user_email and key:
success, msg = send_user_mail(user_email, key)
context = {'activation_msg': msg}
- return my_render_to_response('yaksh/activation_status.html',
- context)
+ return my_render_to_response(
+ 'yaksh/activation_status.html', context
+ )
return index(request)
else:
return my_render_to_response('yaksh/register.html', {'form': form},
context_instance=ci)
else:
form = UserRegisterForm()
- return my_render_to_response('yaksh/register.html', {'form': form},
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/register.html', {'form': form}, context_instance=ci
+ )
def user_logout(request):
@@ -153,8 +160,9 @@ def quizlist_user(request, enrolled=None):
context = {'user': user, 'courses': courses, 'title': title}
- return my_render_to_response("yaksh/quizzes_user.html", context,
- context_instance=ci)
+ return my_render_to_response(
+ "yaksh/quizzes_user.html", context, context_instance=ci
+ )
@login_required
@@ -208,7 +216,10 @@ def add_question(request, question_id=None):
for testcase in TestCase.__subclasses__():
formset = inlineformset_factory(Question, testcase, extra=0,
fields='__all__')
- formsets.append(formset(request.POST, request.FILES, instance=question))
+ formsets.append(formset(
+ request.POST, request.FILES, instance=question
+ )
+ )
files = request.FILES.getlist('file_field')
uploaded_files = FileUpload.objects.filter(question_id=question.id)
if qform.is_valid():
@@ -222,17 +233,23 @@ def add_question(request, question_id=None):
formset.save()
test_case_type = request.POST.get('case_type', None)
else:
- context = {'qform': qform, 'fileform': fileform, 'question': question,
- 'formsets': formsets, 'uploaded_files': uploaded_files}
- return my_render_to_response("yaksh/add_question.html", context,
- context_instance=ci)
+ context = {
+ 'qform': qform,
+ 'fileform': fileform,
+ 'question': question,
+ 'formsets': formsets,
+ 'uploaded_files': uploaded_files
+ }
+ return my_render_to_response(
+ "yaksh/add_question.html", context, context_instance=ci
+ )
qform = QuestionForm(instance=question)
fileform = FileForm()
uploaded_files = FileUpload.objects.filter(question_id=question.id)
formsets = []
for testcase in TestCase.__subclasses__():
- if test_case_type == testcase.__name__.lower():
+ if test_case_type == testcase.__name__.lower():
formset = inlineformset_factory(Question, testcase, extra=1,
fields='__all__')
else:
@@ -241,7 +258,9 @@ def add_question(request, question_id=None):
formsets.append(formset(instance=question))
context = {'qform': qform, 'fileform': fileform, 'question': question,
'formsets': formsets, 'uploaded_files': uploaded_files}
- return my_render_to_response("yaksh/add_question.html", context, context_instance=ci)
+ return my_render_to_response(
+ "yaksh/add_question.html", context, context_instance=ci
+ )
@login_required
@@ -276,9 +295,10 @@ def add_quiz(request, course_id, quiz_id=None):
form = QuizForm(user=user,course=course_id, instance=quiz)
context["quiz_id"] = quiz_id
context["form"] = form
- return my_render_to_response('yaksh/add_quiz.html',
- context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/add_quiz.html', context, context_instance=ci
+ )
+
@login_required
@has_profile
@@ -290,19 +310,19 @@ def prof_manage(request, msg=None):
ci = RequestContext(request)
if user.is_authenticated() and is_moderator(user):
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
- )
+ 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
+ )
if request.method == "POST":
delete_paper = request.POST.getlist('delete_paper')
for answerpaper_id in delete_paper:
answerpaper = AnswerPaper.objects.get(id=answerpaper_id)
qpaper = answerpaper.question_paper
- if qpaper.quiz.course.is_trial == True:
+ if qpaper.quiz.course.is_trial:
qpaper.quiz.course.delete()
else:
if qpaper.answerpaper_set.count() == 1:
@@ -312,16 +332,21 @@ def prof_manage(request, msg=None):
users_per_paper = []
for paper in question_papers:
answer_papers = AnswerPaper.objects.filter(question_paper=paper)
- users_passed = AnswerPaper.objects.filter(question_paper=paper,
- passed=True).count()
- users_failed = AnswerPaper.objects.filter(question_paper=paper,
- passed=False).count()
+ users_passed = AnswerPaper.objects.filter(
+ question_paper=paper, passed=True
+ ).count()
+ users_failed = AnswerPaper.objects.filter(
+ question_paper=paper,
+ passed=False
+ ).count()
temp = paper, answer_papers, users_passed, users_failed
users_per_paper.append(temp)
context = {'user': user, 'users_per_paper': users_per_paper,
'trial_paper': trial_paper, 'msg': msg
}
- return my_render_to_response('yaksh/moderator_dashboard.html', context, context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/moderator_dashboard.html', context, context_instance=ci
+ )
return my_redirect('/exam/login/')
@@ -375,7 +400,7 @@ def start(request, questionpaper_id=None, attempt_num=None):
if not quest_paper.quiz.course.is_enrolled(user):
raise Http404('You are not allowed to view this page!')
# prerequisite check and passing criteria
- if quest_paper.quiz.is_expired():
+ if quest_paper.quiz.is_expired() or not quest_paper.quiz.course.active:
if is_moderator(user):
return redirect("/exam/manage")
return redirect("/exam/quizzes")
@@ -387,16 +412,24 @@ def start(request, questionpaper_id=None, attempt_num=None):
last_attempt = AnswerPaper.objects.get_user_last_attempt(
questionpaper=quest_paper, user=user)
if last_attempt and last_attempt.is_attempt_inprogress():
- return show_question(request, last_attempt.current_question(), last_attempt)
+ return show_question(
+ request, last_attempt.current_question(), last_attempt
+ )
# allowed to start
if not quest_paper.can_attempt_now(user):
if is_moderator(user):
return redirect("/exam/manage")
return redirect("/exam/quizzes")
- attempt_number = 1 if not last_attempt else last_attempt.attempt_number + 1
+ if not last_attempt:
+ attempt_number = 1
+ else:
+ last_attempt.attempt_number + 1
if attempt_num is None:
- context = {'user': user, 'questionpaper': quest_paper,
- 'attempt_num': attempt_number}
+ context = {
+ 'user': user,
+ 'questionpaper': quest_paper,
+ 'attempt_num': attempt_number
+ }
if is_moderator(user):
context["user"] = "moderator"
return my_render_to_response('yaksh/intro.html', context,
@@ -422,22 +455,36 @@ def show_question(request, question, paper, error_message=None, notification=Non
user = request.user
if not question:
msg = 'Congratulations! You have successfully completed the quiz.'
- return complete(request, msg, paper.attempt_number, paper.question_paper.id)
+ return complete(
+ request, msg, paper.attempt_number, paper.question_paper.id
+ )
if not paper.question_paper.quiz.active:
reason = 'The quiz has been deactivated!'
- return complete(request, reason, paper.attempt_number, paper.question_paper.id)
+ return complete(
+ request, reason, paper.attempt_number, paper.question_paper.id
+ )
if paper.time_left() <= 0:
- reason='Your time is up!'
- return complete(request, reason, paper.attempt_number, paper.question_paper.id)
+ reason = 'Your time is up!'
+ return complete(
+ request, reason, paper.attempt_number, paper.question_paper.id
+ )
if question in paper.questions_answered.all():
- notification = 'You have already attempted this question successfully' \
- if question.type == "code" else \
+ notification = (
+ 'You have already attempted this question successfully'
+ if question.type == "code" else
'You have already attempted this question'
+ )
test_cases = question.get_test_cases()
files = FileUpload.objects.filter(question_id=question.id, hide=False)
- context = {'question': question, 'paper': paper, 'error_message': error_message,
- 'test_cases': test_cases, 'files': files, 'notification': notification,
- 'last_attempt': question.snippet.encode('unicode-escape')}
+ context = {
+ 'question': question,
+ 'paper': paper,
+ 'error_message': error_message,
+ 'test_cases': test_cases,
+ 'files': files,
+ 'notification': notification,
+ 'last_attempt': question.snippet.encode('unicode-escape')
+ }
answers = paper.get_previous_answers(question)
if answers:
last_attempt = answers[0].answer
@@ -451,8 +498,10 @@ def show_question(request, question, paper, error_message=None, notification=Non
@email_verified
def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None):
user = request.user
- paper = get_object_or_404(AnswerPaper, user=request.user, attempt_number=attempt_num,
- question_paper=questionpaper_id)
+ paper = get_object_or_404(
+ AnswerPaper, user=request.user, attempt_number=attempt_num,
+ question_paper=questionpaper_id
+ )
question = get_object_or_404(Question, pk=q_id)
if request.method == 'POST' and question.type == 'code':
@@ -474,8 +523,12 @@ def skip(request, q_id, next_q=None, attempt_num=None, questionpaper_id=None):
def check(request, q_id, attempt_num=None, questionpaper_id=None):
"""Checks the answers of the user for particular question"""
user = request.user
- paper = get_object_or_404(AnswerPaper, user=request.user, attempt_number=attempt_num,
- question_paper=questionpaper_id)
+ paper = get_object_or_404(
+ AnswerPaper,
+ user=request.user,
+ attempt_number=attempt_num,
+ question_paper=questionpaper_id
+ )
current_question = get_object_or_404(Question, pk=q_id)
if request.method == 'POST':
@@ -488,9 +541,9 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
user_answer = int(request.POST.get('answer'))
except ValueError:
msg = "Please enter an Integer Value"
- return show_question(request, current_question,
- paper, notification=msg
- )
+ return show_question(
+ request, current_question, paper, notification=msg
+ )
elif current_question.type == 'float':
try:
user_answer = float(request.POST.get('answer'))
@@ -509,8 +562,9 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
assignment_filename = request.FILES.getlist('assignment')
if not assignment_filename:
msg = "Please upload assignment file"
- return show_question(request, current_question, paper, notification=msg)
-
+ return show_question(
+ request, current_question, paper, notification=msg
+ )
for fname in assignment_filename:
assignment_files = AssignmentUpload.objects.filter(
assignmentQuestion=current_question,
@@ -523,14 +577,16 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
question_paper=questionpaper_id)
os.remove(assign_file.assignmentFile.path)
assign_file.delete()
- AssignmentUpload.objects.create(user=user,
- assignmentQuestion=current_question, assignmentFile=fname,
- question_paper_id=questionpaper_id
- )
+ AssignmentUpload.objects.create(
+ user=user, 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 = 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)
@@ -540,22 +596,26 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
user_answer = snippet_code + "\n" + user_code if snippet_code else user_code
if not user_answer:
msg = ["Please submit a valid option or code"]
- return show_question(request, current_question, paper, notification=msg)
- new_answer = Answer(question=current_question, answer=user_answer,
- correct=False, error=json.dumps([]))
+ return show_question(
+ request, current_question, paper, notification=msg
+ )
+ new_answer = Answer(
+ question=current_question, answer=user_answer,
+ correct=False, error=json.dumps([])
+ )
new_answer.save()
paper.answers.add(new_answer)
# If we were not skipped, we were asked to check. For any non-mcq
# questions, we obtain the results via XML-RPC with the code executed
# safely in a separate process (the code_server.py) running as nobody.
json_data = current_question.consolidate_answer_data(user_answer, user) \
- if current_question.type == 'code' or \
- current_question.type == 'upload' else None
- result = paper.validate_answer(user_answer, current_question,
- json_data
- )
+ if current_question.type == 'code' or \
+ current_question.type == 'upload' else None
+ result = paper.validate_answer(
+ user_answer, current_question, json_data
+ )
if result.get('success'):
- new_answer.marks = (current_question.points * result['weight'] /
+ new_answer.marks = (current_question.points * result['weight'] /
current_question.get_maximum_test_case_weight()) \
if current_question.partial_grading and \
current_question.type == 'code' or current_question.type == 'upload' \
@@ -583,7 +643,6 @@ def check(request, q_id, attempt_num=None, questionpaper_id=None):
else:
return show_question(request, current_question, paper)
-
@login_required
@email_verified
def quit(request, reason=None, attempt_num=None, questionpaper_id=None):
@@ -608,12 +667,14 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None):
return my_render_to_response('yaksh/complete.html', context)
else:
q_paper = QuestionPaper.objects.get(id=questionpaper_id)
- paper = AnswerPaper.objects.get(user=user, question_paper=q_paper,
- attempt_number=attempt_num)
+ paper = AnswerPaper.objects.get(
+ user=user, question_paper=q_paper,
+ attempt_number=attempt_num
+ )
paper.update_marks()
paper.set_end_time(timezone.now())
message = reason or "Quiz has been submitted"
- context = {'message': message, 'paper': paper}
+ context = {'message': message, 'paper': paper}
return my_render_to_response('yaksh/complete.html', context)
@@ -637,13 +698,14 @@ def add_course(request, course_id=None):
new_course.save()
return my_redirect('/exam/manage/')
else:
- return my_render_to_response('yaksh/add_course.html',
- {'form': form},
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/add_course.html', {'form': form}, context_instance=ci
+ )
else:
form = CourseForm(instance=course)
- return my_render_to_response('yaksh/add_course.html', {'form': form},
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/add_course.html', {'form': form}, context_instance=ci
+ )
@login_required
@@ -653,8 +715,10 @@ def enroll_request(request, course_id):
ci = RequestContext(request)
course = get_object_or_404(Course, pk=course_id)
if not course.is_active_enrollment and course.hidden:
- msg = 'Unable to add enrollments for this course, please contact your '\
+ msg = (
+ 'Unable to add enrollments for this course, please contact your '
'instructor/administrator.'
+ )
return complete(request, msg, attempt_num=None, questionpaper_id=None)
course.request(user)
@@ -706,8 +770,9 @@ def course_detail(request, course_id):
if not course.is_creator(user) and not course.is_teacher(user):
raise Http404('This course does not belong to you')
- return my_render_to_response('yaksh/course_detail.html', {'course': course},
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/course_detail.html', {'course': course}, context_instance=ci
+ )
@login_required
@@ -720,8 +785,11 @@ def enroll(request, course_id, user_id=None, was_rejected=False):
course = get_object_or_404(Course, pk=course_id)
if not course.is_active_enrollment:
- msg = 'Enrollment for this course has been closed, please contact your '\
+ msg = (
+ 'Enrollment for this course has been closed,'
+ ' please contact your '
'instructor/administrator.'
+ )
return complete(request, msg, attempt_num=None, questionpaper_id=None)
if not course.is_creator(user) and not course.is_teacher(user):
@@ -732,8 +800,9 @@ def enroll(request, course_id, user_id=None, was_rejected=False):
else:
enroll_ids = [user_id]
if not enroll_ids:
- return my_render_to_response('yaksh/course_detail.html', {'course': course},
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/course_detail.html', {'course': course}, context_instance=ci
+ )
users = User.objects.filter(id__in=enroll_ids)
course.enroll(was_rejected, *users)
return course_detail(request, course_id)
@@ -790,9 +859,10 @@ def reject(request, course_id, user_id=None, was_enrolled=False):
reject_ids = [user_id]
if not reject_ids:
message = "Please select atleast one User"
- return my_render_to_response('yaksh/course_detail.html',
- {'course': course, "message": message},
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/course_detail.html', {'course': course, 'message': message},
+ context_instance=ci
+ )
users = User.objects.filter(id__in=reject_ids)
course.reject(was_enrolled, *users)
return course_detail(request, course_id)
@@ -855,13 +925,17 @@ def monitor(request, quiz_id=None):
raise Http404('You are not allowed to view this page!')
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)
+ 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)
@@ -878,15 +952,25 @@ def monitor(request, quiz_id=None):
else:
latest_attempts = []
papers = AnswerPaper.objects.filter(question_paper=q_paper).order_by(
- 'user__profile__roll_number')
+ 'user__profile__roll_number'
+ )
users = papers.values_list('user').distinct()
for auser in users:
last_attempt = papers.filter(user__in=auser).aggregate(
- 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": quiz, "msg": "Quiz Results",
- 'latest_attempts': latest_attempts}
+ 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": quiz,
+ "msg": "Quiz Results",
+ "latest_attempts": latest_attempts
+ }
return my_render_to_response('yaksh/monitor.html', context,
context_instance=ci)
@@ -911,17 +995,19 @@ def ajax_questions_filter(request):
filter_dict['language'] = str(language)
questions = list(Question.objects.filter(**filter_dict))
- return my_render_to_response('yaksh/ajax_question_filter.html',
- {'questions': questions})
+ return my_render_to_response(
+ 'yaksh/ajax_question_filter.html', {'questions': questions}
+ )
def _get_questions(user, question_type, marks):
if question_type is None and marks is None:
return None
if question_type:
- questions = Question.objects.filter(type=question_type,
- user=user,
- active=True
+ questions = Question.objects.filter(
+ type=question_type,
+ user=user,
+ active=True
)
if marks:
questions = questions.filter(points=marks)
@@ -1020,11 +1106,20 @@ def design_questionpaper(request, quiz_id, questionpaper_id=None):
question_paper.save()
random_sets = question_paper.random_questions.all()
fixed_questions = question_paper.get_ordered_questions()
- context = {'qpaper_form': qpaper_form, 'filter_form': filter_form, 'qpaper':
- question_paper, 'questions': questions, 'fixed_questions': fixed_questions,
- 'state': state, 'random_sets': random_sets}
- return my_render_to_response('yaksh/design_questionpaper.html', context,
- context_instance=RequestContext(request))
+ context = {
+ 'qpaper_form': qpaper_form,
+ 'filter_form': filter_form,
+ 'qpaper': question_paper,
+ 'questions': questions,
+ 'fixed_questions': fixed_questions,
+ 'state': state,
+ 'random_sets': random_sets
+ }
+ return my_render_to_response(
+ 'yaksh/design_questionpaper.html',
+ context,
+ context_instance=RequestContext(request)
+ )
@login_required
@@ -1038,6 +1133,18 @@ def show_all_questions(request):
if not is_moderator(user):
raise Http404("You are not allowed to view this page !")
+ questions = Question.objects.filter(user_id=user.id, active=True)
+ form = QuestionFilterForm(user=user)
+ user_tags = questions.values_list('tags', flat=True).distinct()
+ all_tags = Tag.objects.filter(id__in = user_tags)
+ upload_form = UploadFileForm()
+ context['questions'] = questions
+ context['all_tags'] = all_tags
+ context['papers'] = []
+ context['question'] = None
+ context['form'] = form
+ context['upload_form'] = upload_form
+
if request.method == 'POST':
if request.POST.get('delete') == 'delete':
data = request.POST.getlist('question')
@@ -1068,8 +1175,9 @@ def show_all_questions(request):
question = Question()
zip_file = question.dump_questions(question_ids, user)
response = HttpResponse(content_type='application/zip')
- response['Content-Disposition'] = dedent(\
- '''attachment; filename={0}_questions.zip'''.format(user))
+ response['Content-Disposition'] = dedent(
+ '''attachment; filename={0}_questions.zip'''.format(user)
+ )
zip_file.seek(0)
response.write(zip_file.read())
return response
@@ -1086,17 +1194,19 @@ def show_all_questions(request):
else:
context["msg"] = "Please select atleast one question to test"
- questions = Question.objects.filter(user_id=user.id, active=True)
- form = QuestionFilterForm(user=user)
- upload_form = UploadFileForm()
- context['papers'] = []
- context['question'] = None
- context['questions'] = questions
- context['form'] = form
- context['upload_form'] = upload_form
+ if request.POST.get('question_tags'):
+ question_tags = request.POST.getlist("question_tags")
+ search_tags = []
+ for tags in question_tags:
+ search_tags.extend(re.split('[; |, |\*|\n]',tags))
+ search_result = Question.objects.filter(tags__name__in=search_tags,
+ user=user).distinct()
+ context['questions'] = search_result
+
return my_render_to_response('yaksh/showquestions.html', context,
context_instance=ci)
+
@login_required
@email_verified
def user_data(request, user_id, questionpaper_id=None):
@@ -1111,6 +1221,7 @@ def user_data(request, user_id, questionpaper_id=None):
return my_render_to_response('yaksh/user_data.html', context,
context_instance=RequestContext(request))
+
@login_required
@email_verified
def download_csv(request, questionpaper_id):
@@ -1157,6 +1268,7 @@ def download_csv(request, questionpaper_id):
writer.writerow(row)
return response
+
@login_required
@email_verified
def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
@@ -1172,10 +1284,12 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
is_trial=False).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)
+ questionpaper_id = QuestionPaper.objects.filter(
+ quiz_id=quiz_id
+ ).values("id")
+ user_details = AnswerPaper.objects.get_users_for_questionpaper(
+ questionpaper_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):
@@ -1184,13 +1298,16 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
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
- }
+ 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\
- (questionpaper_id, user_id)
+ attempts = AnswerPaper.objects.get_user_all_attempts(
+ questionpaper_id, user_id
+ )
try:
if attempt_number is None:
attempt_number = attempts[0].attempt_number
@@ -1201,14 +1318,18 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
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,
- "has_user_assignments": has_user_assignments,
- "has_quiz_assignments": has_quiz_assignments
- }
+ 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,
+ "has_user_assignments": has_user_assignments,
+ "has_quiz_assignments": has_quiz_assignments
+ }
if request.method == "POST":
papers = data['papers']
for paper in papers:
@@ -1222,10 +1343,9 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None):
'comments_%d' % paper.question_paper.id, 'No comments')
paper.save()
-
- 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
+ )
@login_required
@@ -1267,17 +1387,20 @@ def edit_profile(request):
form_data.user.last_name = request.POST['last_name']
form_data.user.save()
form_data.save()
- return my_render_to_response('yaksh/profile_updated.html',
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/profile_updated.html', context_instance=ci
+ )
else:
context['form'] = form
- return my_render_to_response('yaksh/editprofile.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/editprofile.html', context, context_instance=ci
+ )
else:
form = ProfileForm(user=user, instance=profile)
context['form'] = form
- return my_render_to_response('yaksh/editprofile.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/editprofile.html', context, context_instance=ci
+ )
@login_required
@@ -1295,19 +1418,26 @@ def search_teacher(request, course_id):
context['course'] = course
if user != course.creator and user not in course.teachers.all():
- raise Http404('You are not allowed to view this page!')
+ raise Http404('You are not allowed to view this page!')
if request.method == 'POST':
u_name = request.POST.get('uname')
if not len(u_name) == 0:
- teachers = User.objects.filter(Q(username__icontains=u_name)|
- Q(first_name__icontains=u_name)|Q(last_name__icontains=u_name)|
- Q(email__icontains=u_name)).exclude(Q(id=user.id)|Q(is_superuser=1)|
- Q(id=course.creator.id))
+ teachers = User.objects.filter(
+ Q(username__icontains=u_name) |
+ Q(first_name__icontains=u_name) |
+ Q(last_name__icontains=u_name) |
+ Q(email__icontains=u_name)
+ ).exclude(
+ Q(id=user.id) |
+ Q(is_superuser=1) |
+ Q(id=course.creator.id)
+ )
context['success'] = True
context['teachers'] = teachers
- return my_render_to_response('yaksh/addteacher.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/addteacher.html', context, context_instance=ci
+ )
@login_required
@@ -1335,18 +1465,20 @@ def add_teacher(request, course_id):
course.add_teachers(*teachers)
context['status'] = True
context['teachers_added'] = teachers
- return my_render_to_response('yaksh/addteacher.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/addteacher.html', context, context_instance=ci
+ )
@login_required
@email_verified
def remove_teachers(request, course_id):
- """ remove user from a course """
+ """ remove user from a course """
user = request.user
course = get_object_or_404(Course, pk=course_id)
- if not is_moderator(user) and (user != course.creator and user not in course.teachers.all()):
+ if not is_moderator(user) and (user != course.creator and user
+ not in course.teachers.all()):
raise Http404('You are not allowed to view this page!')
if request.method == "POST":
@@ -1362,14 +1494,16 @@ def test_mode(user, godmode=False, questions_list=None, quiz_id=None):
if questions_list is not None:
trial_course = Course.objects.create_trial_course(user)
trial_quiz = Quiz.objects.create_trial_quiz(trial_course, user)
- trial_questionpaper = QuestionPaper.objects\
- .create_trial_paper_to_test_questions\
- (trial_quiz, questions_list)
+ trial_questionpaper = QuestionPaper.objects.create_trial_paper_to_test_questions(
+ trial_quiz, questions_list
+ )
else:
- trial_quiz = Quiz.objects.create_trial_from_quiz(quiz_id, user, godmode)
- trial_questionpaper = QuestionPaper.objects\
- .create_trial_paper_to_test_quiz\
- (trial_quiz, quiz_id)
+ trial_quiz = Quiz.objects.create_trial_from_quiz(
+ quiz_id, user, godmode
+ )
+ trial_questionpaper = QuestionPaper.objects.create_trial_paper_to_test_quiz(
+ trial_quiz, quiz_id
+ )
return trial_questionpaper
@@ -1394,10 +1528,12 @@ 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)
- has_user_assignment = AssignmentUpload.objects.filter(user=user,
- question_paper_id=questionpaper_id).exists()
+ 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}
+ "has_user_assignment": has_user_assignment}
return my_render_to_response('yaksh/view_answerpaper.html', context)
else:
return my_redirect('/exam/quizzes/')
@@ -1456,24 +1592,25 @@ def regrade(request, course_id, question_id=None, answerpaper_id=None, questionp
details.append(answerpaper.regrade(question_id))
return grader(request, extra_context={'details': details})
+
@login_required
@email_verified
def download_course_csv(request, course_id):
user = request.user
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
- course = get_object_or_404(Course,pk=course_id)
+ course = get_object_or_404(Course, pk=course_id)
if not course.is_creator(user) and not course.is_teacher(user):
raise Http404('The question paper does not belong to your course')
- students = course.get_only_students().annotate(roll_number=F('profile__roll_number'),
- institute=F('profile__institute')
- )\
- .values("id", "first_name", "last_name",
- "email","institute",
- "roll_number"
- )
+ students = course.get_only_students().annotate(
+ roll_number=F('profile__roll_number'),
+ institute=F('profile__institute')
+ ).values(
+ "id", "first_name", "last_name",
+ "email", "institute", "roll_number"
+ )
quizzes = Quiz.objects.filter(course=course, is_trial=False)
-
+
for student in students:
total_course_marks = 0.0
user_course_marks = 0.0
@@ -1481,24 +1618,23 @@ def download_course_csv(request, course_id):
quiz_best_marks = AnswerPaper.objects.get_user_best_of_attempts_marks\
(quiz, student["id"])
user_course_marks += quiz_best_marks
- total_course_marks += quiz.questionpaper_set.values_list\
- ("total_marks", flat=True)[0]
+ total_course_marks += quiz.questionpaper_set.values_list(
+ "total_marks", flat=True)[0]
student["{}".format(quiz.description)] = quiz_best_marks
student["total_scored"] = user_course_marks
student["out_of"] = total_course_marks
-
-
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="{0}.csv"'.format(
(course.name).lower().replace('.', ''))
- header = ['first_name', 'last_name', "roll_number","email", "institute"]\
- +[quiz.description for quiz in quizzes] + ['total_scored', 'out_of']
- writer = csv.DictWriter(response,fieldnames=header, extrasaction='ignore')
+ header = ['first_name', 'last_name', "roll_number", "email", "institute"]\
+ + [quiz.description for quiz in quizzes] + ['total_scored', 'out_of']
+ writer = csv.DictWriter(response, fieldnames=header, extrasaction='ignore')
writer.writeheader()
for student in students:
writer.writerow(student)
return response
+
def activate_user(request, key):
ci = RequestContext(request)
profile = get_object_or_404(Profile, activation_key=key)
@@ -1506,8 +1642,9 @@ def activate_user(request, key):
context['success'] = False
if profile.is_email_verified:
context['activation_msg'] = "Your account is already verified"
- return my_render_to_response('yaksh/activation_status.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/activation_status.html', context, context_instance=ci
+ )
if timezone.now() > profile.key_expiry_time:
context['msg'] = dedent("""
@@ -1519,8 +1656,10 @@ def activate_user(request, key):
profile.is_email_verified = True
profile.save()
context['msg'] = "Your account is activated"
- return my_render_to_response('yaksh/activation_status.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/activation_status.html', context, context_instance=ci
+ )
+
def new_activation(request, email=None):
ci = RequestContext(request)
@@ -1533,19 +1672,21 @@ def new_activation(request, email=None):
except MultipleObjectsReturned:
context['email_err_msg'] = "Multiple entries found for this email"\
"Please change your email"
- return my_render_to_response('yaksh/activation_status.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/activation_status.html', context, context_instance=ci
+ )
except ObjectDoesNotExist:
context['success'] = False
context['msg'] = "Your account is not verified. \
Please verify your account"
- return render_to_response('yaksh/activation_status.html',
- context, context_instance=ci)
+ return render_to_response(
+ 'yaksh/activation_status.html', context, context_instance=ci
+ )
if not user.profile.is_email_verified:
user.profile.activation_key = generate_activation_key(user.username)
user.profile.key_expiry_time = timezone.now() + \
- timezone.timedelta(minutes=20)
+ timezone.timedelta(minutes=20)
user.profile.save()
new_user_data = User.objects.get(email=email)
success, msg = send_user_mail(new_user_data.email,
@@ -1558,8 +1699,10 @@ def new_activation(request, email=None):
else:
context['activation_msg'] = "Your account is already verified"
- return my_render_to_response('yaksh/activation_status.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/activation_status.html', context, context_instance=ci
+ )
+
def update_email(request):
context = {}
@@ -1573,8 +1716,10 @@ def update_email(request):
return new_activation(request, email)
else:
context['email_err_msg'] = "Please Update your email"
- return my_render_to_response('yaksh/activation_status.html', context,
- context_instance=ci)
+ return my_render_to_response(
+ 'yaksh/activation_status.html', context, context_instance=ci
+ )
+
@login_required
@email_verified
@@ -1583,10 +1728,9 @@ def download_assignment_file(request, quiz_id, question_id=None, user_id=None):
if not is_moderator(user):
raise Http404("You are not allowed to view this page")
qp = QuestionPaper.objects.get(quiz_id=quiz_id)
- assignment_files, file_name = AssignmentUpload.objects.get_assignments(qp,
- question_id,
- user_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:
@@ -1595,8 +1739,9 @@ def download_assignment_file(request, quiz_id, question_id=None, user_id=None):
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.write(
+ f_name.assignmentFile.path, folder_name
+ )
zip_file.close()
zipfile_name.seek(0)
response = HttpResponse(content_type='application/zip')
@@ -1606,6 +1751,7 @@ def download_assignment_file(request, quiz_id, question_id=None, user_id=None):
response.write(zipfile_name.read())
return response
+
@login_required
@email_verified
def duplicate_course(request, course_id):