summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh')
-rw-r--r--yaksh/forms.py7
-rw-r--r--yaksh/models.py4
-rw-r--r--yaksh/static/yaksh/js/requesthandler.js5
-rw-r--r--yaksh/templates/yaksh/add_quiz.html7
-rw-r--r--yaksh/templates/yaksh/course_modules.html36
-rw-r--r--yaksh/templates/yaksh/question.html23
-rw-r--r--yaksh/templates/yaksh/quizzes_user.html89
-rw-r--r--yaksh/test_models.py20
-rw-r--r--yaksh/test_views.py30
-rw-r--r--yaksh/views.py21
10 files changed, 169 insertions, 73 deletions
diff --git a/yaksh/forms.py b/yaksh/forms.py
index a51e6c2..57140bc 100644
--- a/yaksh/forms.py
+++ b/yaksh/forms.py
@@ -282,8 +282,11 @@ class CourseForm(forms.ModelForm):
class Meta:
model = Course
- fields = ['name', 'enrollment', 'active', 'code', 'instructions',
- 'start_enroll_time', 'end_enroll_time', 'grading_system']
+ fields = [
+ 'name', 'enrollment', 'active', 'code', 'instructions',
+ 'start_enroll_time', 'end_enroll_time', 'grading_system',
+ 'view_grade'
+ ]
class ProfileForm(forms.ModelForm):
diff --git a/yaksh/models.py b/yaksh/models.py
index cce90e7..7e0364a 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -758,6 +758,7 @@ class Course(models.Model):
teachers = models.ManyToManyField(User, related_name='teachers')
is_trial = models.BooleanField(default=False)
instructions = models.TextField(default=None, null=True, blank=True)
+ view_grade = models.BooleanField(default=False)
learning_module = models.ManyToManyField(LearningModule,
related_name='learning_module')
@@ -1408,6 +1409,9 @@ class FileUpload(models.Model):
self.hide = True
self.save()
+ def get_filename(self):
+ return os.path.basename(self.file.name)
+
###############################################################################
class Answer(models.Model):
diff --git a/yaksh/static/yaksh/js/requesthandler.js b/yaksh/static/yaksh/js/requesthandler.js
index 952de3a..7ccdef0 100644
--- a/yaksh/static/yaksh/js/requesthandler.js
+++ b/yaksh/static/yaksh/js/requesthandler.js
@@ -197,6 +197,11 @@ if (question_type == 'upload' || question_type == 'code') {
reset_editor = function() {
global_editor.editor.setValue(init_val);
global_editor.editor.clearHistory();
+ $('#undo_changes').modal('hide');
+ }
+
+ confirm = function(){
+ $("#undo_changes").modal("show");
}
});
function user_arranged_options(){
diff --git a/yaksh/templates/yaksh/add_quiz.html b/yaksh/templates/yaksh/add_quiz.html
index c955e65..0762f10 100644
--- a/yaksh/templates/yaksh/add_quiz.html
+++ b/yaksh/templates/yaksh/add_quiz.html
@@ -37,8 +37,13 @@
{% if quiz and course_id %}
{% if quiz.questionpaper_set.get.id %}
<center>
+ <a href="{{URL_ROOT}}/exam/manage/designquestionpaper/{{ quiz.id }}/{{quiz.questionpaper_set.get.id}}/{{course_id}}" class="btn btn-primary">Edit Question Paper</a>
+ <a href="{{URL_ROOT}}/exam/manage/preview_questionpaper/{{quiz.questionpaper_set.get.id}}" class="btn btn-primary" target="_blank">
+ Preview Question Paper
+ </a>
+ <br>
+ <br>
<h4>You can check the quiz by attempting it in the following modes:</h4>
- <a href="{{URL_ROOT}}/exam/manage/designquestionpaper/{{ quiz.id }}/{{quiz.questionpaper_set.get.id}}/{{course_id}}" class="btn btn-primary">View Question Paper</a>
<button class="btn btn-outline-info" type="button" name="button" onClick='usermode("{{URL_ROOT}}/exam/manage/usermode/{{quiz.id}}/{{course_id}}/");'>User Mode</button>
<button class="btn btn-outline-info" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/manage/godmode/{{quiz.id}}/{{course_id}}/");'>
diff --git a/yaksh/templates/yaksh/course_modules.html b/yaksh/templates/yaksh/course_modules.html
index 917f78c..d5bbfd3 100644
--- a/yaksh/templates/yaksh/course_modules.html
+++ b/yaksh/templates/yaksh/course_modules.html
@@ -2,7 +2,6 @@
{% load custom_filters %}
{% block title %} Course Modules {% endblock %}
{% block script %}
-<script src="{{ URL_ROOT }}/static/yaksh/js/donutpiechart.js"></script>
<script>
function view_unit(unit){
$("#"+unit+"_down").toggle();
@@ -17,35 +16,24 @@
<div class="container">
<div class="row justify-content-md-center yakshwell ">
<div class="col-md-10 bg-light card">
- <div class="row align-items-center">
- <div class="col h4"> {{ course.name }} </div>
- <div class="col-md-3 ml-auto yakshwell">
- <div class="row align-items-center">
- <div class="col-sm-6"> Overall
- Course</br>Completion :
- </div>
- <div class="col-sm-5">
- <span class="progress">
- <span class="progress-bar bg-warning " role="progressbar" style="width: {{ course_percentage }}%; color: black;" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">{{ course_percentage }} % completed</span>
- </span>
- </div>
- </div>
- </div>
+ <div class="row align-items-center my-3">
+ <div class="col h4 text-center"> {{ course.name }} </div>
</div>
</div>
</div>
<center>
-<div class=" col-md-8">
-<b>Grade: {% if grade %} {{ grade }} {% else %} Will be available once the course is complete {% endif %}</b>
-</div>
-
+ {% if course.view_grade %}
+ <div class=" col-md-8">
+ <b>Grade: {% if grade %} {{ grade }} {% else %} Will be available once the course is complete {% endif %}</b>
+ </div>
+ {% endif %}
-{% if msg %}
- <div class="col-md-8 alert alert-warning animated flash" role="alert">
- {{ msg }}
- </div>
-{% endif %}
+ {% if msg %}
+ <div class="col-md-8 alert alert-warning animated flash" role="alert">
+ {{ msg }}
+ </div>
+ {% endif %}
</center>
<div class="row justify-content-md-center ">
diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html
index da77702..cb6d90a 100644
--- a/yaksh/templates/yaksh/question.html
+++ b/yaksh/templates/yaksh/question.html
@@ -160,7 +160,7 @@ question_type = "{{ question.type }}"
<span> Files to download for this question </span> <hr>
{% for f_name in files %}
<div class="yakshwell">
- <a href="{{f.file.url}}" class="btn btn-outline-secondary"><b>{{forloop.counter}}.</b> {{f_name.file.name}}</a>
+ <a href="{{f_name.file.url}}" class="btn btn-outline-secondary btn-sm " target="_blank">{{f_name.get_filename}}</a>
<br>
</div>
{% endfor %}
@@ -271,7 +271,7 @@ question_type = "{{ question.type }}"
<h5>Write your program below:</h5>
</div>
<div class="col-md-3 ml-auto">
- <a href="#answer" class=" btn btn-outline-primary" onclick="reset_editor()" name="reset" id="reset">Undo Changes&nbsp;<span class="glyphicon glyphicon-refresh"></span></a>
+ <a href="#answer" class=" btn btn-outline-primary" onclick="confirm()" name="reset" id="reset">Undo Changes&nbsp;<span class="glyphicon glyphicon-refresh"></span></a>
</div>
</div>
<div class="yakshwell">
@@ -335,5 +335,24 @@ question_type = "{{ question.type }}"
</div>
</div>
</div>
+
+ <!-- UNDO CHANGES Modal -->
+ <div class="modal" id="undo_changes" >
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title" id="myModalLabel">Are you Sure?</h4>
+ </div>
+ <div id = "modal_body"class="modal-body">
+ <font color="brown"><b>Your code will be reset.</b></font>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-warning" onclick="reset_editor()">OK</button>
+ <button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
{% endblock main %}
diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html
index 548eef4..ee5b684 100644
--- a/yaksh/templates/yaksh/quizzes_user.html
+++ b/yaksh/templates/yaksh/quizzes_user.html
@@ -72,21 +72,21 @@
<div class="yakshwell">
<div class="row yakshlabel align-items-center">
<div class="col">
- <h4><b>
-
- {{ course.name }} by {{ course.creator.get_full_name }}
-
- </b></h4>
- {% if course.is_active_enrollment %}
+ <a data-toggle="collapse" href="#collapsedetails{{course.data.id}}" role="button" aria-expanded="false" aria-controls="#collapsedetails{{course.data.id}}">
+ <h4><b>
+ {{ course.data.name }} by {{ course.data.creator.get_full_name }}
+ </b></h4>
+ </a>
+ {% if course.data.is_active_enrollment %}
<div class="text-left">
- <span class="yakshgreen">{{course.start_enroll_time}}</span>&nbsp;&nbsp; to &nbsp;&nbsp;<span class="yakshgreen">{{course.end_enroll_time}}</span>
+ <span class="yakshgreen">{{course.data.start_enroll_time}}</span>&nbsp;&nbsp; to &nbsp;&nbsp;<span class="yakshgreen">{{course.data.end_enroll_time}}</span>
</div>
{% endif %}
</div>
<div class="col-sm-auto">
- {% if course.days_before_start != 0 %}
+ {% if course.data.days_before_start != 0 %}
<span class="label label-info" style="font-size: 15px">
- {{course.days_before_start}} day(s) to start
+ {{course.data.days_before_start}} day(s) to start
</span>
{% endif %}
@@ -94,20 +94,27 @@
<div class="container col-sm-4 offset-sm-2">
<span class="row align-items-center">
<span class="col-sm-4" >
- <a class="btn btn-primary" data-toggle="collapse" href="#collapsedetails{{course.id}}" role="button" aria-expanded="false" aria-controls="#collapsedetails{{course.id}}">DETAILS</a>
+ <a class="btn btn-primary" data-toggle="collapse" href="#collapsedetails{{course.data.id}}" role="button" aria-expanded="false" aria-controls="#collapsedetails{{course.data.id}}">DETAILS</a>
</span>
<span class="col-sm-auto">
- {% if user in course.requests.all %} <span class="badge badge-warning">Request Pending </span>
- {% elif user in course.rejected.all %}<span class="badge badge-danger">Request Rejected</span>
- {% elif user in course.students.all %}<a class="btn btn-success" href="{{URL_ROOT}}/exam/course_modules/{{course.id}}" >START</a>
+ {% if user in course.data.requests.all %} <span class="badge badge-warning">Request Pending </span>
+ {% elif user in course.data.rejected.all %}<span class="badge badge-danger">Request Rejected</span>
+ {% elif user in course.data.students.all %}
+ <a class="btn btn-success" href="{{URL_ROOT}}/exam/course_modules/{{course.data.id}}" >
+ {% if course.completion_percentage > 0 %}
+ CONTINUE
+ {% else %}
+ START
+ {% endif %}
+ </a>
{% else %}
- {% if course.active %}
- {% if course.is_active_enrollment %}
- {% if course.is_self_enroll %}
- <a class="btn btn-success" href="{{ URL_ROOT }}/exam/self_enroll/{{ course.id }}">ENROLL</a>
+ {% if course.data.active %}
+ {% if course.data.is_active_enrollment %}
+ {% if course.data.is_self_enroll %}
+ <a class="btn btn-success" href="{{ URL_ROOT }}/exam/self_enroll/{{ course.data.id }}">ENROLL</a>
{% else %}
- <a class="btn btn-success" href="{{ URL_ROOT }}/exam/enroll_request/{{ course.id }}">ENROLL</a>
+ <a class="btn btn-success" href="{{ URL_ROOT }}/exam/enroll_request/{{ course.data.id }}">ENROLL</a>
{% endif %}
{% else %}
<span class="btn btn-danger disabled" style="font-size: 15px">
@@ -124,39 +131,55 @@
</span>
</div>
<!-- About course-->
- <div class="collapse container-fluid" id="collapsedetails{{course.id}}">
+ <div class="collapse container-fluid" id="collapsedetails{{course.data.id}}">
<div class="card card-body ">
- <h4>{{ course.name }} by {{ course.creator.get_full_name }}</h4><hr>
+ <h4>{{ course.data.name }} by {{ course.data.creator.get_full_name }}</h4><hr>
<div class="row">
<div class="col-md-7">
- {% if course.description %}
+ {% if course.data.description %}
<p> <span class="yakshred yakshheading">About the course</span><br>
- {{ course.description }}
+ {{ course.data.description }}
</p>
{% endif %}
- {% if course.get_learning_modules %}
+ {% if course.data.get_learning_modules %}
<p> <span class="yakshred yakshheading">What you'll learn</span>
<ul>
- {% for module in course.get_learning_modules %}
+ {% for module in course.data.get_learning_modules %}
<li>{{module.name|title}}</li>
{% endfor %}
</ul>
</p>
{% endif %}
<p> <span class="yakshred yakshheading">Instructor</span><br>
- {{ course.creator.get_full_name }}
+ {{ course.data.creator.get_full_name }}
</p>
- {% if course.instructions %}
- <p> <span class="yakshred yakshheading">Requirement(s)</span><br>
- {{ course.instructions|safe }}
+ {% if course.data.instructions %}
+ <p> <span class="yakshred yakshheading">Instructions</span><br>
+ {{ course.data.instructions|safe }}
</p>
{% endif %}
</div>
- <div class="col-md-4 ">
- <table class="table table-borderless card table-responsive-sm">
- <tr><td class="yakshgreen">STARTS ON</td> <td>{{course.start_enroll_time}}</td></tr>
- <tr><td class="yakshgreen">ENDS ON</td> <td>{{course.end_enroll_time}}</td>
- </table>
+ <div class="col-md-4">
+ <div class="row my-3">
+ <div class="col-md-5">
+ STARTS ON
+ </div>
+ <div class="col-md-7">
+ {{course.data.start_enroll_time}}
+ </div>
+ </div>
+ <div class="row my-3">
+ <div class="col-md-5">
+ ENDS ON
+ </div>
+ <div class="col-md-7">
+ {{course.data.end_enroll_time}}
+ </div>
+ </div>
+ <div class="row my-3">
+ <div class="progress-bar bg-success" role="progressbar" style="width:{{course.completion_percentage}}%"; color: black;" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">{{course.completion_percentage}} % completed
+ </div>
+ </div>
</div>
</div>
</div>
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index 1f38d03..374fb29 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -1,5 +1,6 @@
import unittest
from django.contrib.auth.models import Group
+from django.core.files.uploadedfile import SimpleUploadedFile
from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\
QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\
StdIOBasedTestCase, FileUpload, McqTestCase, AssignmentUpload,\
@@ -2130,3 +2131,22 @@ class CourseStatusTestCases(unittest.TestCase):
# Test get course grade after completion
self.assertEqual(self.course.get_grade(self.answerpaper1.user), 'B')
+
+
+class FileUploadTestCases(unittest.TestCase):
+ def setUp(self):
+ self.question = Question.objects.get(summary='Q1')
+ self.filename = "uploadtest.txt"
+ self.uploaded_file = SimpleUploadedFile(self.filename, b'Test File')
+ self.file_upload = FileUpload.objects.create(
+ file=self.uploaded_file,
+ question=self.question
+ )
+
+ def test_get_file_name(self):
+ self.assertEqual(self.file_upload.get_filename(), self.filename)
+
+ def tearDown(self):
+ if os.path.isfile(self.file_upload.file.path):
+ os.remove(self.file_upload.file.path)
+ self.file_upload.delete()
diff --git a/yaksh/test_views.py b/yaksh/test_views.py
index 274bcda..4c1f5b9 100644
--- a/yaksh/test_views.py
+++ b/yaksh/test_views.py
@@ -420,10 +420,14 @@ class TestStudentDashboard(TestCase):
response = self.client.get(reverse('yaksh:quizlist_user'),
follow=True
)
+ courses_in_context = {
+ 'data': self.course,
+ 'completion_percentage': None,
+ }
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "yaksh/quizzes_user.html")
self.assertEqual(response.context['title'], 'All Courses')
- self.assertEqual(response.context['courses'][0], self.course)
+ self.assertEqual(response.context['courses'][0], courses_in_context)
def test_student_dashboard_enrolled_courses_get(self):
"""
@@ -439,10 +443,14 @@ class TestStudentDashboard(TestCase):
kwargs={'enrolled': "enrolled"}),
follow=True
)
+ courses_in_context = {
+ 'data': self.course,
+ 'completion_percentage': 0,
+ }
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "yaksh/quizzes_user.html")
self.assertEqual(response.context['title'], 'Enrolled Courses')
- self.assertEqual(response.context['courses'][0], self.course)
+ self.assertEqual(response.context['courses'][0], courses_in_context)
def test_student_dashboard_hidden_courses_post(self):
"""
@@ -456,10 +464,14 @@ class TestStudentDashboard(TestCase):
response = self.client.post(reverse('yaksh:quizlist_user'),
data={'course_code': 'hide'}
)
+ courses_in_context = {
+ 'data': self.hidden_course,
+ 'completion_percentage': None,
+ }
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "yaksh/quizzes_user.html")
self.assertEqual(response.context['title'], 'Search')
- self.assertEqual(response.context['courses'][0], self.hidden_course)
+ self.assertEqual(response.context['courses'][0], courses_in_context)
class TestMonitor(TestCase):
@@ -5017,19 +5029,25 @@ class TestQuestionPaper(TestCase):
)
self.assertEqual(response.status_code, 404)
- def test_preview_qustionpaper_without_quiz_owner(self):
+ def test_preview_questionpaper_without_quiz_owner(self):
self.client.login(
username=self.teacher.username,
password=self.teacher_plaintext_pass
)
- # Should raise an HTTP 404 response
+ # Should pass successfully
response = self.client.get(
reverse('yaksh:preview_questionpaper',
kwargs={"questionpaper_id": self.question_paper.id}
)
)
- self.assertEqual(response.status_code, 404)
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, 'yaksh/preview_questionpaper.html')
+ self.assertEqual(
+ response.context['questions'],
+ self.questions_list
+ )
+ self.assertEqual(response.context['paper'], self.question_paper)
def test_mcq_attempt_right_after_wrong(self):
""" Case:- Check if answerpaper and answer marks are updated after
diff --git a/yaksh/views.py b/yaksh/views.py
index 6c7a12e..94ef19b 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -156,6 +156,7 @@ def user_logout(request):
def quizlist_user(request, enrolled=None, msg=None):
"""Show All Quizzes that is available to logged-in user."""
user = request.user
+ courses_data = []
if request.method == "POST":
course_code = request.POST.get('course_code')
@@ -164,18 +165,30 @@ def quizlist_user(request, enrolled=None, msg=None):
title = 'Search'
elif enrolled is not None:
- courses = user.students.all()
+ courses = user.students.all().order_by('-id')
title = 'Enrolled Courses'
else:
courses = Course.objects.filter(
active=True, is_trial=False
).exclude(
~Q(requests=user), ~Q(rejected=user), hidden=True
- )
+ ).order_by('-id')
title = 'All Courses'
+ for course in courses:
+ if user in course.students.all():
+ _percent = course.get_completion_percent(user)
+ else:
+ _percent = None
+ courses_data.append(
+ {
+ 'data': course,
+ 'completion_percentage': _percent,
+ }
+ )
+
context = {
- 'user': user, 'courses': courses,
+ 'user': user, 'courses': courses_data,
'title': title, 'msg': msg
}
@@ -2825,8 +2838,6 @@ def preview_questionpaper(request, questionpaper_id):
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
paper = QuestionPaper.objects.get(id=questionpaper_id)
- if not paper.quiz.creator == user:
- raise Http404('This questionpaper does not belong to you')
context = {
'questions': paper._get_questions_for_answerpaper(),
'paper': paper,