summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.txt25
-rw-r--r--online_test/__init__.py2
-rw-r--r--yaksh/forms.py7
-rw-r--r--yaksh/migrations/0014_release_0_9_1.py21
-rw-r--r--yaksh/models.py8
-rw-r--r--yaksh/static/yaksh/css/yakshcustom.css14
-rw-r--r--yaksh/static/yaksh/js/requesthandler.js5
-rw-r--r--yaksh/templates/exam.html34
-rw-r--r--yaksh/templates/yaksh/add_quiz.html7
-rw-r--r--yaksh/templates/yaksh/complete.html16
-rw-r--r--yaksh/templates/yaksh/course_detail.html31
-rw-r--r--yaksh/templates/yaksh/course_modules.html43
-rw-r--r--yaksh/templates/yaksh/design_questionpaper.html33
-rw-r--r--yaksh/templates/yaksh/monitor.html56
-rw-r--r--yaksh/templates/yaksh/question.html39
-rw-r--r--yaksh/templates/yaksh/quit.html16
-rw-r--r--yaksh/templates/yaksh/quizzes_user.html89
-rw-r--r--yaksh/templates/yaksh/show_video.html31
-rw-r--r--yaksh/test_models.py20
-rw-r--r--yaksh/test_views.py30
-rw-r--r--yaksh/views.py50
21 files changed, 370 insertions, 207 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 5aa0cc3..d122a9f 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,4 +1,27 @@
-=== 0.9 (13-07-2018) ===
+=== 0.9.1 (07-02-2019) ===
+
+* Changed routing so that opening the base URL will redirect user to /exam
+* Updated storage hierarchy of uploaded assignments so that they are stored
+ per course and per quiz
+* Deprecated yaksh cli.py script
+* Changed and Upgraded UI
+* Fixed a bug where assigning moderator privileges with create_moderator
+ command did not set is_moderator to True
+* Fixed a bug that caused incorrect rendering of Unit Completion
+* Fixed a bug to allow escaping of special characters in rendered answers
+* Fixed a bug that fetched the same course multiple times when the user is
+ creator and teacher
+* Deprecated the 'course_completion_percent' custom template tag
+* Fixed overall Course Completion percentage in Student interface
+* Fixed the broken Monitor interface UI
+* Fixed a bug to remove user as teacher of any course if is_moderator is set
+ to False
+* Fixed the broken Create Question Paper interface UI
+* Improve the Question Legend in Exam interface
+* Fixed embed video link modal alignment in Add Lesson and Add Module
+ interface
+
+=== 0.9.0 (13-07-2018) ===
* Questions can be searched using tags while creating/editing question papers.
* Fixed a bug that would not select all questions in Question page.
diff --git a/online_test/__init__.py b/online_test/__init__.py
index e46aee1..8969d49 100644
--- a/online_test/__init__.py
+++ b/online_test/__init__.py
@@ -1 +1 @@
-__version__ = '0.9'
+__version__ = '0.9.1'
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/migrations/0014_release_0_9_1.py b/yaksh/migrations/0014_release_0_9_1.py
new file mode 100644
index 0000000..a15c0e0
--- /dev/null
+++ b/yaksh/migrations/0014_release_0_9_1.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2019-02-07 10:41
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('yaksh', '0013_release_0_9_0'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='assignmentupload',
+ name='course',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='yaksh.Course'),
+ ),
+ ]
diff --git a/yaksh/models.py b/yaksh/models.py
index 1e96ae1..eb18bb7 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -803,6 +803,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')
@@ -1453,6 +1454,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):
@@ -1645,7 +1649,9 @@ class QuestionPaper(models.Model):
attempts = AnswerPaper.objects.get_total_attempt(questionpaper=self,
user=user,
course_id=course_id)
- return attempts != self.quiz.attempts_allowed
+ attempts_allowed = attempts < self.quiz.attempts_allowed
+ infinite_attempts = self.quiz.attempts_allowed == -1
+ return attempts_allowed or infinite_attempts
def can_attempt_now(self, user, course_id):
if self._is_attempt_allowed(user, course_id):
diff --git a/yaksh/static/yaksh/css/yakshcustom.css b/yaksh/static/yaksh/css/yakshcustom.css
index a9b4349..4aba382 100644
--- a/yaksh/static/yaksh/css/yakshcustom.css
+++ b/yaksh/static/yaksh/css/yakshcustom.css
@@ -1,9 +1,5 @@
-
-@import url('https://fonts.googleapis.com/css?family=Dosis|Exo+2');
-
/* Navbar */
-
.yakshnav {
background-color: #142624;
color: white;
@@ -139,6 +135,10 @@ html {
min-height: 100%;
}
+.question-nav-bg {
+ background-color:#B4B8BA;
+}
+
.yaksh {
font-size: 15px;
font-family: 'Dosis', sans-serif;
@@ -225,6 +225,12 @@ html {
.table-wrapper-2 {
display: block;
max-height: 500px;
+ padding-top: 1em;
+ width: 100%;
overflow-y: auto;
-ms-overflow-style: -ms-autohiding-scrollbar;
}
+
+#card{
+ flex-wrap: wrap;
+} \ No newline at end of file
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/exam.html b/yaksh/templates/exam.html
index 29ad167..d439c64 100644
--- a/yaksh/templates/exam.html
+++ b/yaksh/templates/exam.html
@@ -8,7 +8,7 @@
<span class="navbar-toggler-icon" style="color: white"></span>
</button>
<a class="navbar-brand">
- <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH" style="margin-top: -3px; margin-left:-15px">
+ <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH">
</img>
</a>
<div class="collapse navbar-collapse col-md-6" id="myNavbar">
@@ -24,8 +24,7 @@
{% endif %}
<span class="fa fa-power-off"></span></button></span>
</form>
-
- </div>
+ </div>
</div><!-- /.navbar -->
</div><!-- /.container -->
</nav><!-- /.navbar -->
@@ -57,15 +56,15 @@
{% endif %}
{% endif %}
{% if qid in paper.get_questions_answered %}
- <a class=" btn btn-outline-success " style="background-color:#B4B8BA;" href="#" data-toggle="tooltip"
+ <a class="btn btn-outline-light question-nav-bg" href="#" data-toggle="tooltip"
onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')"
title="{{ qid.description }}">{{ forloop.counter }}</a>
{% endif %}
{% else %}
{% if qid.id == question.id %}
- <a class="active btn btn-outline-success " data-toggle="tooltip" title="{{ qid.description|striptags }}">{{ forloop.counter }}</a>
+ <a class="active btn btn-outline-success" data-toggle="tooltip" title="{{ qid.description|striptags }}">{{ forloop.counter }}</a>
{% elif qid in paper.get_questions_answered %}
- <a class=" btn btn-outline-success " style="background-color:#B4B8BA;" href="#" data-toggle="tooltip"
+ <a class="btn btn-outline-success question-nav-bg" href="#" data-toggle="tooltip"
onclick="call_skip('{{ URL_ROOT }}/exam/{{ question.id }}/skip/{{ qid.id }}/{{ paper.attempt_number }}/{{ module.id }}/{{ paper.question_paper.id }}/{{course.id}}/')"
title="{{ qid.description }}">{{ forloop.counter }}</a>
{% else %}
@@ -112,26 +111,3 @@
</div>
{% endblock %}
-
-{% block footer %}
- <!--footer-->
- <footer class="container-fluid yakshsidebarfooter text-center">
- <div class="row justify-content-center">
- <div class="col-sm-5 ">
- {% if user %}
- {% block info %}
- <b>{{user.get_full_name|title}}</b> with Roll no. <b>{{user.profile.roll_number}}</b> is logged in as <b>{{user.username}}</b>
- {% endblock %}
- {% endif %}
- </div>
- <div class="col-sm-2">
- |
- </div>
- <div class="col-sm-4 text-left">
- <b>Any Queries?</b> Email : info@fossee.in
- </div>
- </div>
- </footer>
- <!--footer end-->
-{% endblock %}
-
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/complete.html b/yaksh/templates/yaksh/complete.html
index cced41c..a3324a6 100644
--- a/yaksh/templates/yaksh/complete.html
+++ b/yaksh/templates/yaksh/complete.html
@@ -1,11 +1,15 @@
{% extends "base.html" %}
-{% block pagetitle %}
-<div class="yakshnav fixed-top" style=" padding-top: 0.5%;padding-bottom: 0.5%;">
- <a class="navbar-brand" href="{{ URL_ROOT }}/exam/" >
- <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH">
- </img>
- </a>
+{% block nav %}
+<div class="container-fluid yakshnav">
+ <nav class="navbar fixed-top navbar-expand-lg yakshheading yakshnav">
+ <div class="container">
+ <a class="navbar-brand">
+ <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH">
+ </img>
+ </a>
+ </div><!-- /.container -->
+ </nav><!-- /.navbar -->
</div>
{% endblock %}
diff --git a/yaksh/templates/yaksh/course_detail.html b/yaksh/templates/yaksh/course_detail.html
index a0a6ed2..f75e362 100644
--- a/yaksh/templates/yaksh/course_detail.html
+++ b/yaksh/templates/yaksh/course_detail.html
@@ -132,17 +132,26 @@
{% elif state == "course_status" %}
<div class="course_data">
- <center><div class="yakshlabel">
- <input type="hidden" id="course_name" value="{{course.name}}">
- <a href="#" class="btn btn-outline-success pull-right" id="export">Export to CSV</a><h5>Course Status</h5>
- </div></center>
+ <center>
+ <div class="row">
+ <div class="col">
+ <h5>Course Status</h5>
+ </div>
+ <div class="col-md-8">
+ Number Of Students: {{ student_details | length }}
+ </div>
+ <div class="col">
+ <input type="hidden" id="course_name" value="{{course.name}}">
+ <a href="#" class="btn btn-outline-success" id="export">Export to CSV</a>
+ </div>
+ </div>
+ </center>
<div class="yakshwell">
<table class="tablesorter table table-bordered table-responsive-sm" id="course_table" data-sortlist="[0,0]">
<thead>
<tr class="yakshlight">
- <th>Sr No.</th>
<th>Roll No.</th>
- <th>Email</th>
+ <th>Name</th>
<th>Current Unit</th>
<th>Course Completion Percentage</th>
<th>Grade</th>
@@ -151,26 +160,18 @@
<tbody>
{% for student, grade, percent, unit in student_details %}
<tr>
- <td width="5%">
- {{forloop.counter}}.
- </td>
<td>
{{ student.profile.roll_number}}
</td>
<td width="50%">
<a class="user_data" data-item-id="{{course.id}}+{{student.id}}" data-toggle="tooltip" title="Click to view Overall Course progress" data-placement="top">
- {% if student.email %}
- {{ student.email }}
- {% else %}
- {{ student.get_full_name|title}}
- {% endif %}
+ {{ student.get_full_name|title}}
<i class="fa fa-caret-down"></i>
</a>
<div id="show_status_{{course.id}}_{{student.id}}" style="display: None;">
</div>
</td>
<td>
- {{ student.get_full_name|title }}
{% if unit %}
{% if unit.type == 'quiz' %}
{{unit.quiz.description}}
diff --git a/yaksh/templates/yaksh/course_modules.html b/yaksh/templates/yaksh/course_modules.html
index 917f78c..e1fdc51 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();
@@ -15,37 +14,33 @@
{% block main %}
<div class="container">
-<div class="row justify-content-md-center yakshwell ">
- <div class="col-md-10 bg-light card">
+<div class="row justify-content-md-center yakshwell">
+ <div class="col-md-10 bg-light card" id="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 = "col">
+ {% if course.has_lessons %}
+ <a href="{% url 'yaksh:download_course' course.id %}" data-toggle="tooltip" title="Download course content" class="btn btn-primary pull-right">
+ Download Course
+ </a>
+ {% endif %}
+ </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/design_questionpaper.html b/yaksh/templates/yaksh/design_questionpaper.html
index bf1f23e..0ab7cc0 100644
--- a/yaksh/templates/yaksh/design_questionpaper.html
+++ b/yaksh/templates/yaksh/design_questionpaper.html
@@ -113,7 +113,14 @@ select
<li>
<label>
<input type="checkbox" name="questions" data-qid="{{question.id}}" value={{question.id}}>
- <span> {{ question.summary }} </span> <span> {{ question.points }} </span>
+ <span>
+ {% if user == question.user %}
+ <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a>
+ {% else %}
+ {{question.summary}}
+ {% endif %}
+ </span>
+ <span> {{ question.points }}</span>
</label>
</li>
{% endfor %}
@@ -134,7 +141,13 @@ select
<label>
<input type="checkbox" name="added-questions"
data-qid="{{question.id}}" value={{question.id}}>
- <span> {{ question.summary }} </span>
+ <span>
+ {% if user == question.user %}
+ <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a>
+ {% else %}
+ {{question.summary}}
+ {% endif %}
+ </span>
<span> {{ question.points }} </span>
</label>
</li>
@@ -175,7 +188,13 @@ select
<li>
<label>
<input type="checkbox" name="random_questions" data-qid="{{question.id}}" value={{question.id}}>
- <span> {{ question.summary }} </span> <span> {{ question.points }} </span>
+ <span>
+ {% if user == question.user %}
+ <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a>
+ {% else %}
+ {{question.summary}}
+ {% endif %}</span>
+ <span> {{ question.points }} </span>
</label>
</li>
{% endfor %}
@@ -201,7 +220,13 @@ select
{% for question in random_set.questions.all %}
<li>
<label>
- <span> {{ question.summary }} </span> <span> {{ question.points }} </span>
+ <span>
+ {% if user == question.user %}
+ <a href="{{URL_ROOT}}/exam/manage/addquestion/{{ question.id }}" target="_blank">{{ question.summary }}</a>
+ {% else %}
+ {{question.summary}}
+ {% endif %}</span>
+ <span> {{ question.points }} </span>
</label>
</li>
{% endfor %}
diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html
index 1f85938..a9f8328 100644
--- a/yaksh/templates/yaksh/monitor.html
+++ b/yaksh/templates/yaksh/monitor.html
@@ -68,32 +68,49 @@ $(document).ready(function()
{% if quiz %}
{% if papers %}
<div class="row">
- <div class="card col-md-4">
- <div class="row">
- <div class="col"><b>Course Name:<br>Quiz Name:<br>Number of papers:<br>Papers completed:<br>Papers in progress:</b>
- </div>
- <div class="col">
- {{ course.name }}<br>
- {{ quiz.description }}<br>
- {{ papers|length }}<br>
- {% completed papers as completed_papers %}
- {# template tag used to get the count of completed papers #}
- <b class="yakshred"> {{ completed_papers }} </b><br>
- {% inprogress papers as inprogress_papers %}
- {# template tag used to get the count of inprogress papers #}
- <b class="yakshred"> {{ inprogress_papers }} </b>
- </div>
+ <div class="card col-md-10">
+ <div class = "table-responsive"">
+ <table class = "table">
+ <tr>
+ <td><b>Course Name:&nbsp</b></td>
+ <td>{{course.name}}</td>
+ </tr>
+ <tr>
+ <td><b>Quiz Name:&nbsp</b></td>
+ <td>{{quiz.description}}</td>
+ </tr>
+ <tr>
+ <td><b>Number of papers: &nbsp</b></td>
+ <td>{{papers|length}}</td>
+ </tr>
+ <tr>
+ <td><b>Papers Completed: &nbsp</b></td>
+ <td>
+ {% completed papers as completed_papers %}
+ <b class = "yakshgreen">{{completed_papers}}</b>
+ </td>
+ </tr>
+ <tr>
+ <td><b>Papers in progress: &nbsp</b></td>
+ <td>
+ {% inprogress papers as inprogress_papers %}
+ <b class="yakshred"> {{ inprogress_papers }} </b>
+ </td>
+ </tr>
+ </table>
</div>
</div>
- <div class="col">
+ <div class = "row">
+ <div class="col-md-2">
<p><a href="{{URL_ROOT}}/exam/manage/statistics/question/{{papers.0.question_paper.id}}/{{course.id}}" class="btn btn-primary">Question Statisitics</a></p>
<p>
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#csvModal">
Download CSV <span class="fa fa-download"></span>
- </button></p>
+ </button>
+ </p>
+ </div>
</div>
- <div class="yakshwell container-fluid">
- <div class="table-wrapper-2">
+ <div class="table-wrapper-2">
<table id="result-table" class="tablesorter table table-striped table-responsive-sm">
<thead>
<tr class="table-info">
@@ -120,7 +137,6 @@ $(document).ready(function()
<td> {{ paper.answers.count }} </td>
<td id="time_left{{forloop.counter0}}"> {{ paper.time_left }} </td>
<td>{{ paper.status }}</td>
- </div>
</tr>
{% endfor %}
</tbody>
diff --git a/yaksh/templates/yaksh/question.html b/yaksh/templates/yaksh/question.html
index da77702..f13de1a 100644
--- a/yaksh/templates/yaksh/question.html
+++ b/yaksh/templates/yaksh/question.html
@@ -122,8 +122,8 @@ question_type = "{{ question.type }}"
<div class="card ">
<div class="col-md-12 bg-light">
<div class="row align-items-center ">
- <div class="col yakshheading"> {{ question.summary }} </div>
- <div class="col-md-4 ml-auto yakshwell text-center">
+ <div class="col-md-6 yakshheading"> {{ question.summary }} </div>
+ <div class="col-md-3 ml-auto yakshwell text-center">
{% if question.type == "mcq" %}
SINGLE CORRECT CHOICE
{% elif question.type == "mcc" %}
@@ -147,8 +147,16 @@ question_type = "{{ question.type }}"
ARRANGE THE OPTIONS IN CORRECT ORDER
{% endif %}
</div>
- <div class="col-md-1 ml-auto text-center">
- <span class="badge badge-warning">{{ question.points }}</span><br>Marks
+ <div class="col-md-2 ml-auto text-center">
+ <div class="row">
+ <div class="col-md-6">
+ <h5>
+ <span class="badge badge-warning">
+ {{ question.points }} Marks
+ </span>
+ </h5>
+ </div>
+ </div>
</div>
</div>
</div>
@@ -160,7 +168,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 +279,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 +343,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/quit.html b/yaksh/templates/yaksh/quit.html
index 3d22746..dd06ff9 100644
--- a/yaksh/templates/yaksh/quit.html
+++ b/yaksh/templates/yaksh/quit.html
@@ -1,11 +1,15 @@
{% extends "base.html" %}
-{% block pagetitle %}
-<div class="yakshnav fixed-top" style=" padding-top: 0.5%;padding-bottom: 0.5%;">
- <a class="navbar-brand" href="{{ URL_ROOT }}/exam/" >
- <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH">
- </img>
- </a>
+{% block nav %}
+<div class="container-fluid yakshnav">
+ <nav class="navbar fixed-top navbar-expand-lg yakshheading yakshnav">
+ <div class="container">
+ <a class="navbar-brand">
+ <img src="{{ URL_ROOT }}/static/yaksh/images/yaksh_banner.png" alt="YAKSH">
+ </img>
+ </a>
+ </div><!-- /.container -->
+ </nav><!-- /.navbar -->
</div>
{% endblock %}
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/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html
index 9f92bc3..9d24b44 100644
--- a/yaksh/templates/yaksh/show_video.html
+++ b/yaksh/templates/yaksh/show_video.html
@@ -94,37 +94,6 @@
{% if learning_module.html_data%}
{% endif %}
</div>
- <div class="yakshwell col-md-3">
- <div class="bg-light">
- {% if learning_module.get_learning_units %}
- <center><h4>Units in this module</h4></center><hr>
- {% for unit in learning_module.get_learning_units %}
- <div class="row justify-content-center">
- <span class="col-sm-2 yakshgreen">
- {% if unit.type == "quiz" %}
- {% if unit.quiz.is_exercise %}
- <span class="fa fa-pencil"></span>
- {% else %}
- <span class="fa fa-puzzle-piece"></span>
- {% endif %}
- {% else %}
- <span class="fa fa-book"></span>
- {% endif %}
- </span>
- <span class="col-sm-7">
- {% if unit.type == "quiz" %}
- {{unit.quiz.description}}
- {% else %}
- {{unit.lesson.name}}
- {% endif %}
- </span>
- </div>
- {% endfor %}
- {% else %}
- <center><h3>No Lessons/Quizzes Found</h3></center>
- {% endif %}
- </div>
- </div>
</div>
<div class="yakshwell text-center">
{% if first_unit %}
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index 1adf64a..4d91b27 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,\
@@ -2175,3 +2176,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 255d614..ee7c911 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 526c774..d634e0c 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
}
@@ -523,23 +536,28 @@ def start(request, questionpaper_id=None, attempt_num=None, course_id=None,
# if any previous attempt
last_attempt = AnswerPaper.objects.get_user_last_attempt(
quest_paper, user, course_id)
- if last_attempt and last_attempt.is_attempt_inprogress():
- return show_question(
- request, last_attempt.current_question(), last_attempt,
- course_id=course_id, module_id=module_id,
- previous_question=last_attempt.current_question()
- )
+
+ if last_attempt:
+ if last_attempt.is_attempt_inprogress():
+ return show_question(
+ request, last_attempt.current_question(), last_attempt,
+ course_id=course_id, module_id=module_id,
+ previous_question=last_attempt.current_question()
+ )
+ attempt_number = last_attempt.attempt_number + 1
+ else:
+ attempt_number = 1
+
# allowed to start
if not quest_paper.can_attempt_now(user, course_id)[0]:
msg = quest_paper.can_attempt_now(user, course_id)[1]
if is_moderator(user):
return prof_manage(request, msg=msg)
- return view_module(request, module_id=module_id, course_id=course_id,
- msg=msg)
- if not last_attempt:
- attempt_number = 1
- else:
- attempt_number = last_attempt.attempt_number + 1
+ return complete(
+ request, msg, last_attempt.attempt_number, quest_paper.id,
+ course_id=course_id, module_id=module_id
+ )
+
if attempt_num is None and not quest_paper.quiz.is_exercise:
context = {
'user': user,
@@ -2855,8 +2873,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,