summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh')
-rw-r--r--yaksh/code_server.py5
-rw-r--r--yaksh/forms.py3
-rw-r--r--yaksh/models.py67
-rw-r--r--yaksh/static/yaksh/js/lesson.js11
-rw-r--r--yaksh/static/yaksh/js/show_toc.js2
-rw-r--r--yaksh/templates/base.html17
-rw-r--r--yaksh/templates/manage.html7
-rw-r--r--yaksh/templates/user.html8
-rw-r--r--yaksh/templates/yaksh/add_lesson.html28
-rw-r--r--yaksh/templates/yaksh/add_video_quiz.html6
-rw-r--r--yaksh/templates/yaksh/course_forum.html2
-rw-r--r--yaksh/templates/yaksh/lessons_forum.html2
-rw-r--r--yaksh/templates/yaksh/post_comments.html4
-rw-r--r--yaksh/templates/yaksh/show_lesson_quiz.html17
-rw-r--r--yaksh/templates/yaksh/show_lesson_statistics.html51
-rw-r--r--yaksh/templates/yaksh/show_toc.html30
-rw-r--r--yaksh/templates/yaksh/show_video.html121
-rw-r--r--yaksh/templatetags/custom_filters.py9
-rw-r--r--yaksh/test_models.py15
-rw-r--r--yaksh/test_views.py74
-rw-r--r--yaksh/urls.py2
-rw-r--r--yaksh/views.py28
22 files changed, 330 insertions, 179 deletions
diff --git a/yaksh/code_server.py b/yaksh/code_server.py
index 4feb7fd..60f966f 100644
--- a/yaksh/code_server.py
+++ b/yaksh/code_server.py
@@ -17,7 +17,10 @@ import json
from multiprocessing import Process, Queue, Manager
import os
from os.path import dirname, abspath
-import pwd
+try:
+ import pwd
+except ImportError:
+ pass
import sys
import time
diff --git a/yaksh/forms.py b/yaksh/forms.py
index 091505d..d57d388 100644
--- a/yaksh/forms.py
+++ b/yaksh/forms.py
@@ -715,7 +715,8 @@ class VideoQuizForm(forms.ModelForm):
)
self.fields['type'].initial = question_type
self.fields['description'].widget.attrs.update(
- {'class': form_input_class, 'placeholder': 'Description'}
+ {'class': form_input_class, 'placeholder': 'Description',
+ 'id': 'que_description'}
)
self.fields['timer'].widget.attrs.update(
{'class': form_input_class, 'placeholder': 'Quiz Time'}
diff --git a/yaksh/models.py b/yaksh/models.py
index 6f7af53..e2b9952 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -25,6 +25,7 @@ import zipfile
import tempfile
from textwrap import dedent
from ast import literal_eval
+import pandas as pd
# Django Imports
from django.db import models
@@ -2388,15 +2389,24 @@ class AnswerPaper(models.Model):
'error_list': [e for e in json.loads(answer.error)]
}]
+ q_a.update(
+ { q: [] for q in self.questions_unanswered.all() }
+ )
+
for question, answers in q_a.items():
answers = q_a[question]
- q_a[question].append({
- 'marks': max([
- answer['answer'].marks
- for answer in answers
- if question == answer['answer'].question
- ])
- })
+ if answers:
+ q_a[question].append({
+ 'marks': max([
+ answer['answer'].marks
+ for answer in answers
+ if question == answer['answer'].question
+ ]),
+ })
+ else:
+ q_a[question].append({
+ 'marks': 0.0,
+ })
return q_a
@@ -2822,19 +2832,50 @@ class TOCManager(models.Manager):
data = {}
for toc in contents:
data[toc] = LessonQuizAnswer.objects.filter(
- toc_id=toc.id).values_list("toc_id").distinct().count()
+ toc_id=toc.id).values_list(
+ "student_id", flat=True).distinct().count()
return data
def get_question_stats(self, toc_id):
answers = LessonQuizAnswer.objects.get_queryset().filter(
toc_id=toc_id).order_by('id')
- question = answers.first().toc.content_object
- answers = answers.values(
- "student__first_name", "student__last_name", "student__email",
- "student_id", "toc_id"
- ).distinct()
+ question = TableOfContents.objects.get(id=toc_id).content_object
+ if answers.exists():
+ answers = answers.values(
+ "student__first_name", "student__last_name", "student__email",
+ "student_id", "toc_id"
+ )
+ df = pd.DataFrame(answers)
+ answers = df.drop_duplicates().to_dict(orient='records')
return question, answers
+ def get_per_tc_ans(self, toc_id, question_type, is_percent=True):
+ answers = LessonQuizAnswer.objects.filter(toc_id=toc_id).values(
+ "student_id", "answer__answer"
+ ).order_by("id")
+ data = None
+ if answers.exists():
+ df = pd.DataFrame(answers)
+ grp = df.groupby(["student_id"]).tail(1)
+ total_count = grp.count().answer__answer
+ data = grp.groupby(["answer__answer"]).count().to_dict().get(
+ "student_id")
+ if question_type == "mcc":
+ tc_ids = []
+ mydata = {}
+ for i in data.keys():
+ tc_ids.extend(literal_eval(i))
+ for j in tc_ids:
+ if j not in mydata:
+ mydata[j] = 1
+ else:
+ mydata[j] +=1
+ data = mydata.copy()
+ if is_percent:
+ for key, value in data.items():
+ data[key] = (value/total_count)*100
+ return data, total_count
+
def get_answer(self, toc_id, user_id):
submission = LessonQuizAnswer.objects.filter(
toc_id=toc_id, student_id=user_id).last()
diff --git a/yaksh/static/yaksh/js/lesson.js b/yaksh/static/yaksh/js/lesson.js
index 2cc2e62..586ae18 100644
--- a/yaksh/static/yaksh/js/lesson.js
+++ b/yaksh/static/yaksh/js/lesson.js
@@ -1,13 +1,20 @@
$(document).ready(function() {
- MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
var simplemde = new SimpleMDE({
element: document.getElementById("id_description"),
forceSync: true,
hideIcons: ["preview", "side-by-side", "fullscreen"]
});
simplemde.codemirror.on("change", function() {
- MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
$("#description_body").html(simplemde.markdown(simplemde.value()));
+ renderMathInElement(
+ document.body,
+ {
+ delimiters: [
+ {left: "$$", right: "$$", display: false},
+ {left: "$", right: "$", display: true},
+ ]
+ }
+ );
});
const player = new Plyr('#player');
var timer = $("#vtimer");
diff --git a/yaksh/static/yaksh/js/show_toc.js b/yaksh/static/yaksh/js/show_toc.js
index 7d9b68e..a2507d0 100644
--- a/yaksh/static/yaksh/js/show_toc.js
+++ b/yaksh/static/yaksh/js/show_toc.js
@@ -13,7 +13,7 @@ $(document).ready(function() {
});
},
max_height: 400,
- height: 400,
+ height: 200,
plugins: "image code link",
convert_urls: false
});
diff --git a/yaksh/templates/base.html b/yaksh/templates/base.html
index 2cc607c..cba56cb 100644
--- a/yaksh/templates/base.html
+++ b/yaksh/templates/base.html
@@ -52,15 +52,22 @@
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.js" integrity="sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4" crossorigin="anonymous"></script>
<!-- To automatically render math in text elements, include the auto-render extension: -->
- <script defer src="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/contrib/auto-render.min.js" integrity="sha384-mll67QQFJfxn0IYznZYonOWZ644AWYC+Pt2cHqMaRhXVrursRwvLnLaebdGIlYNa" crossorigin="anonymous"
- onload="renderMathInElement(document.body);"></script>
+ <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
+ <script defer src="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/contrib/auto-render.min.js" integrity="sha384-mll67QQFJfxn0IYznZYonOWZ644AWYC+Pt2cHqMaRhXVrursRwvLnLaebdGIlYNa" crossorigin="anonymous">
+ </script>
<script>
new WOW().init();
$(document).ready(function() {
- $(".alert").delay(2000).slideUp(200, function() {
- $(this).alert('close');
- });
+ renderMathInElement(
+ document.body,
+ {
+ delimiters: [
+ {left: "$$", right: "$$", display: false},
+ {left: "$", right: "$", display: true},
+ ]
+ }
+ );
});
</script>
{% block script %}
diff --git a/yaksh/templates/manage.html b/yaksh/templates/manage.html
index 53d5c72..047f784 100644
--- a/yaksh/templates/manage.html
+++ b/yaksh/templates/manage.html
@@ -65,6 +65,13 @@
</ul>
</div>
</nav>
+<script type="text/javascript">
+ $(document).ready(function() {
+ $(".alert").delay(2000).slideUp(200, function() {
+ $(this).alert('close');
+ });
+ });
+</script>
{% endblock %}
{% block content %}
diff --git a/yaksh/templates/user.html b/yaksh/templates/user.html
index 4e3974b..7211d5c 100644
--- a/yaksh/templates/user.html
+++ b/yaksh/templates/user.html
@@ -43,7 +43,13 @@
</nav>
</div>
{% endblock %}
-
+<script type="text/javascript">
+ $(document).ready(function() {
+ $(".alert").delay(2000).slideUp(200, function() {
+ $(this).alert('close');
+ });
+ });
+</script>
{% block content %}
{% block main %}
diff --git a/yaksh/templates/yaksh/add_lesson.html b/yaksh/templates/yaksh/add_lesson.html
index 329a8e0..4400032 100644
--- a/yaksh/templates/yaksh/add_lesson.html
+++ b/yaksh/templates/yaksh/add_lesson.html
@@ -25,8 +25,8 @@
{{error}}
</div>
{% endif %}
- <div class="row justify-content-center form-group">
- <div class="col-md-5 col-md-offset-4">
+ <div class="row">
+ <div class="col-md-6">
<a class="btn btn-primary" href="{% url 'yaksh:get_course_modules' course_id %}">
<i class="fa fa-arrow-left"></i>&nbsp;Back
</a>
@@ -89,9 +89,11 @@
{{lesson_form.video_path}}
<br>
Video File:
- <span class="badge badge-info">
- {{lesson_form.video_file.help_text}}
- </span>
+ <div class="table-responsive">
+ <span class="badge badge-info">
+ {{lesson_form.video_file.help_text}}
+ </span>
+ </div>
<div class="col-md-4">
{{lesson_form.video_file}}
</div>
@@ -143,7 +145,7 @@
</form>
</div>
<br><br>
- <div class="col-md-5">
+ <div class="col-md-6">
<br>
<div class="card">
<div class="card-header">
@@ -152,13 +154,13 @@
</a>
</div>
<div class="collapse show" id="toc-collapse">
- <div class="card-body" id="toc">{{toc}}</div>
+ <div class="card-body" id="toc" style="max-height: 400px; overflow-y: auto;">{{toc}}</div>
</div>
</div>
<br>
<div class="card" id="preview_text_div">
<div class="card-header">
- Setup Lesson
+ Create lesson table of contents
</div>
<div class="card-body">
{% if lesson_form.instance and lesson_form.instance.video_path %}
@@ -210,10 +212,12 @@
</div>
{% endwith %}
{% else %}
- <div class="badge badge-info">
- <strong>
- Add a Video Path or Upload a video file to setup lesson contents
- </strong>
+ <div class="table-responsive">
+ <div class="badge badge-info">
+ <strong>
+ Add a Video Path or Upload a video file to setup lesson contents
+ </strong>
+ </div>
</div>
{% endif %}
</div>
diff --git a/yaksh/templates/yaksh/add_video_quiz.html b/yaksh/templates/yaksh/add_video_quiz.html
index ad087bc..b8a788e 100644
--- a/yaksh/templates/yaksh/add_video_quiz.html
+++ b/yaksh/templates/yaksh/add_video_quiz.html
@@ -76,9 +76,9 @@
$('#id_type').children("option[value='code']").show();
}
});
- function init_editor() {
+ $(function() {
tinymce.init({
- selector : "textarea",
+ selector: 'textarea#que_description',
setup : function(ed) {
ed.on('change', function(e) {
tinymce.triggerSave();
@@ -89,6 +89,6 @@
plugins: "image code link",
convert_urls: false
});
- }
+ });
});
</script> \ No newline at end of file
diff --git a/yaksh/templates/yaksh/course_forum.html b/yaksh/templates/yaksh/course_forum.html
index acd6861..b98688b 100644
--- a/yaksh/templates/yaksh/course_forum.html
+++ b/yaksh/templates/yaksh/course_forum.html
@@ -129,7 +129,7 @@
{% endwith %}
</td>
<td>
- {% if user == course.creator %}
+ {% if user == course.creator or user in course.get_teachers %}
<small><a href="{% url 'yaksh:hide_post' course.id post.uid %}" class="pull-right fa fa-trash"></i></a></small>
{% endif %}
</td>
diff --git a/yaksh/templates/yaksh/lessons_forum.html b/yaksh/templates/yaksh/lessons_forum.html
index 250536d..58fb360 100644
--- a/yaksh/templates/yaksh/lessons_forum.html
+++ b/yaksh/templates/yaksh/lessons_forum.html
@@ -61,7 +61,7 @@
{% endwith %}
</td>
<td>
- {% if user == course.creator %}
+ {% if user == course.creator or user in course.get_teachers %}
<small><a href="{% url 'yaksh:hide_post' course.id post.uid %}" class="pull-right fa fa-trash"></i></a></small>
{% endif %}
</td>
diff --git a/yaksh/templates/yaksh/post_comments.html b/yaksh/templates/yaksh/post_comments.html
index bc452e0..70aac47 100644
--- a/yaksh/templates/yaksh/post_comments.html
+++ b/yaksh/templates/yaksh/post_comments.html
@@ -38,7 +38,7 @@
{% endif %}
</strong>
{{post.created_at}}
- {% if user == course.creator %}<a href="{% url 'yaksh:hide_post' post.target.id post.uid %}" class="pull-right fa fa-trash"></a>{% endif %}
+ {% if user == course.creator or user in course.get_teachers %}<a href="{% url 'yaksh:hide_post' post.target.id post.uid %}" class="pull-right fa fa-trash"></a>{% endif %}
</small>
</div>
@@ -77,7 +77,7 @@
</strong>
</div>
<div class="col-6 text-right">
- <small class="text-muted">{{comment.created_at}} {% if user == course.creator %} <a href="{% url 'yaksh:hide_comment' post.target.id comment.uid %}" class="fa fa-trash"></a>{% endif %}</small>
+ <small class="text-muted">{{comment.created_at}} {% if user == course.creator or user in course.get_teachers %} <a href="{% url 'yaksh:hide_comment' post.target.id comment.uid %}" class="fa fa-trash"></a>{% endif %}</small>
</div>
</div>
<p class="card-text description">{{comment.description|safe}}</p>
diff --git a/yaksh/templates/yaksh/show_lesson_quiz.html b/yaksh/templates/yaksh/show_lesson_quiz.html
index fb5ae6c..82e01bc 100644
--- a/yaksh/templates/yaksh/show_lesson_quiz.html
+++ b/yaksh/templates/yaksh/show_lesson_quiz.html
@@ -1,5 +1,16 @@
{% load custom_filters %}
<script type="text/javascript">
+ $(document).ready(function() {
+ renderMathInElement(
+ document.body,
+ {
+ delimiters: [
+ {left: "$$", right: "$$", display: false},
+ {left: "$", right: "$", display: true},
+ ]
+ }
+ );
+ });
function user_arranged_options() {
var temp_array = []
var add_array = document.getElementById("arrange_order");
@@ -120,11 +131,11 @@
var order_array = $(arrange).sortable(['serialize']);
</script>
{% endif %}
- {% if question.type == "mcq" or question.type == "mcc" or question.type == "integer" or question.type == "float" or question.type == "string" %}
+ {% if question.type == "arrange" %}
+ <br><button class="btn btn-success" type="submit" name="check" id="check" onClick="return user_arranged_options();">Submit</button>
+ {% else %}
<br><button class="btn btn-success" type="submit" name="check" id="check">Submit
</button>
- {% elif question.type == "arrange" %}
- <br><button class="btn btn-success" type="submit" name="check" id="check" onClick="return user_arranged_options();">Submit</button>
{% endif %}
</div>
</div>
diff --git a/yaksh/templates/yaksh/show_lesson_statistics.html b/yaksh/templates/yaksh/show_lesson_statistics.html
index 2bcdd2d..31261f3 100644
--- a/yaksh/templates/yaksh/show_lesson_statistics.html
+++ b/yaksh/templates/yaksh/show_lesson_statistics.html
@@ -102,6 +102,19 @@
</span>
{% endif %}
{{tc.options}}
+ {% if per_tc_ans %}
+ {% get_tc_percent tc.id per_tc_ans as percent %}
+ <div class="progress" style="width: 30%">
+ {% if percent %}
+ <div class="progress-bar bg-success" role="progressbar" aria-valuenow="{{percent}}"
+ aria-valuemin="0" aria-valuemax="100" style="width:{{percent}}%">
+ <b style="color: white;">{{percent}}%</b>
+ </div>
+ {% else %}
+ <b style="color: black;">0%</b>
+ {% endif %}
+ </div>
+ {% endif %}
{% elif question.type == "integer" %}
<span class="badge badge-pill badge-success">Answer:</span>
{{tc.correct}}
@@ -116,33 +129,43 @@
</div>
</div>
<br>
+ <strong>Total Submissions: {{total_count}}</strong>
+ <br><br>
+ {% if question.type != 'mcq' and question.type != 'mcc' %}
+ <div id="plot_div"></div>
+ <script type="text/javascript">
+ var x_data = [];
+ var y_data = [];
+ {% for i, j in per_tc_ans.items %}
+ x_data.push("{{i}}");
+ y_data.push("{{j}}");
+ {% endfor %}
+ var data = [{x: x_data, y: y_data, type: 'bar'}];
+ var layout = {
+ title: "Submission records",
+ xaxis: {title: 'Submitted Value'},
+ yaxis: {title: 'Number of Submissions'}
+ };
+ var config = {responsive: true}
+ Plotly.newPlot('plot_div', data, layout, config);
+ </script>
+ <br><br>
+ {% endif %}
{% include "yaksh/paginator.html" %}
<table class="table table-responsive">
<tr>
<th>Sr No.</th>
<th>Student Name</th>
<th>Email</th>
- <th>Latest Answer</th>
- <th>Status</th>
+ <th>Latest Submission</th>
</tr>
{% for data in objects.object_list %}
<tr>
- <td>{{forloop.counter}}</td>
+ <td>{{ forloop.counter0|add:objects.start_index }}</td>
<td>{{data.student__first_name}} {{data.student__last_name}}</td>
<td>{{data.student__email}}</td>
{% get_answers data.toc_id data.student_id as user_answer %}
<td>{{ user_answer.0 }}</td>
- <td>
- {% if user_answer.1 %}
- <span class="badge badge-success">
- Correct
- </span>
- {% else %}
- <span class="badge badge-secondary">
- Incorrect
- </span>
- {% endif %}
- </td>
</tr>
{% endfor %}
</table>
diff --git a/yaksh/templates/yaksh/show_toc.html b/yaksh/templates/yaksh/show_toc.html
index 92ea0cd..4c8ffe2 100644
--- a/yaksh/templates/yaksh/show_toc.html
+++ b/yaksh/templates/yaksh/show_toc.html
@@ -1,22 +1,24 @@
{% load custom_filters %}
{% has_lesson_video lesson_id as has_video %}
{% if has_video %}
- <div>
- <a href="{% url 'yaksh:download_sample_toc' %}">
- <i class="fa fa-download"></i>&nbsp;Download Sample
- </a>
- <br><br>
- <form action="" method="POST" enctype="multipart/form-data">
- {% csrf_token %}
- <input type="file" name="toc" required="">
- <button class="btn btn-outline-success" id="upload_toc" name="upload_toc">
- <i class="fa fa-upload"></i>&nbsp;Upload TOC
- </button>
- </form>
+ <div class="card">
+ <div class="card-body">
+ <a href="{% url 'yaksh:download_sample_toc' %}">
+ <i class="fa fa-download"></i>&nbsp;Download Sample
+ </a>
+ <hr>
+ <form action="" method="POST" enctype="multipart/form-data">
+ {% csrf_token %}
+ <input type="file" name="toc" required="">
+ <button class="btn btn-outline-success" id="upload_toc" name="upload_toc">
+ <i class="fa fa-upload"></i>&nbsp;Upload TOC
+ </button>
+ </form>
+ </div>
</div>
- <hr>
+ <br>
{% endif %}
-<table class="table table-responsive-sm">
+<table class="table table-responsive">
{% for toc in contents %}
{% with toc.get_toc_text as toc_name %}
<tr>
diff --git a/yaksh/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html
index 6e3cabb..d27293e 100644
--- a/yaksh/templates/yaksh/show_video.html
+++ b/yaksh/templates/yaksh/show_video.html
@@ -140,64 +140,62 @@
{% else %} <!-- Lesson body -->
<!-- Lesson Table of contents -->
<div class="row">
- <div class="col-md-8">
- <div class="card-body">
- {% if lesson.video_path %}
- {% with lesson.video_path|video_name as video %}
- {% if video.1 == "others" %}
- <video id="player" playsinline controls>
- <source src="{{video.0}}" />
- </video>
- {% else %}
- <div id="player" data-plyr-provider="{{video.1}}" data-plyr-embed-id="{{video.0}}"></div>
- {% endif %}
- {% endwith %}
- {% endif %}
- </div>
- </div>
- <div class="col-md-4">
- <div class="card">
- <div class="card-header">
- <a class="card-link" data-toggle="collapse" href="#toc-collapse">
- Table Of Contents&nbsp;<i class="fa fa-angle-down"></i>
- </a>
+ {% if lesson.video_path %}
+ <div class="col-md-8">
+ <div class="card-body">
+ {% with lesson.video_path|video_name as video %}
+ {% if video.1 == "others" %}
+ <video id="player" playsinline controls>
+ <source src="{{video.0}}" />
+ </video>
+ {% else %}
+ <div id="player" data-plyr-provider="{{video.1}}" data-plyr-embed-id="{{video.0}}"></div>
+ {% endif %}
+ {% endwith %}
+ </div>
</div>
- <div class="collapse show" id="toc-collapse">
- <div class="card-body" id="toc">
- <table class="table table-responsive">
- {% for content in toc %}
- {% with content.get_toc_text as toc_name %}
- <tr>
- <td>
- <a href="#" onclick="select_toc(this);" data-toc="{{content.id}}" data-toc-type="{{content.content}}">
- {{ toc_name }}
- </a>
- </td>
- <td>
- {{content.get_content_display}}
- </td>
- <td id="toc_time_{{content.id}}">
- {{content.time}}
- </td>
- <input type="hidden" id="toc_{{content.id}}" value="{% url 'yaksh:get_marker_quiz' course.id content.id %}" data-content="{{content.content}}"/>
- <input type="hidden" id="toc_desc_{{content.id}}" value="{{content.content_object.description|safe}}" data-content="{{content.content}}"/>
- </tr>
- {% endwith %}
- {% empty %}
- <center>
- <span class="badge badge-warning">No Table of contents added</span>
- </center>
- {% endfor %}
- </table>
+ {% if toc %}
+ <div class="col-md-4">
+ <div class="card">
+ <div class="card-header">
+ <a class="card-link" data-toggle="collapse" href="#toc-collapse">
+ Table Of Contents&nbsp;<i class="fa fa-angle-down"></i>
+ </a>
+ </div>
+ <div class="collapse show" id="toc-collapse">
+ <div class="card-body" id="toc" style="max-height: 400px; overflow-y: auto;">
+ <table class="table table-responsive">
+ {% for content in toc %}
+ {% with content.get_toc_text as toc_name %}
+ <tr>
+ <td>
+ <a href="#" onclick="select_toc(this);" data-toc="{{content.id}}" data-toc-type="{{content.content}}">
+ {{ toc_name }}
+ </a>
+ </td>
+ <td>
+ {{content.get_content_display}}
+ </td>
+ <td id="toc_time_{{content.id}}">
+ {{content.time}}
+ </td>
+ <input type="hidden" id="toc_{{content.id}}" value="{% url 'yaksh:get_marker_quiz' course.id content.id %}" data-content="{{content.content}}"/>
+ <input type="hidden" id="toc_desc_{{content.id}}" value="{{content.content_object.description|safe}}" data-content="{{content.content}}"/>
+ </tr>
+ {% endwith %}
+ {% empty %}
+ <center class=table-responsive>
+ <span class="badge badge-warning">No Table of contents added</span>
+ </center>
+ {% endfor %}
+ </table>
+ </div>
+ </div>
</div>
</div>
- </div>
- </div>
+ {% endif %}
+ {% endif %}
<div class="col-md-8">
- <a href="{% url 'yaksh:next_unit' course.id learning_module.id current_unit.id %}" class="btn btn-info btn-lg" >
- Next&nbsp;<i class="fa fa-step-forward"></i>
- </a>
- <br><br>
<div class="card">
<div class="card-header"><h3><strong>Lesson Description</strong></h3></div>
<div class="card-body">
@@ -227,23 +225,28 @@
</div>
</div>
</div>
+ <br>
+ <a href="{% url 'yaksh:next_unit' course.id learning_module.id current_unit.id %}" class="btn btn-info btn-lg" >
+ Next&nbsp;<i class="fa fa-step-forward"></i>
+ </a>
{% endif %}
{% if state == 'lesson' %}
- <div>
- <b><u>Add comment:</u></b>
+ <div class="col-md-8">
+ <hr>
+ <b><u>Comments:</u></b>
<form action="" method="POST" enctype='multipart/form-data'>
<div class="form-group">
{% csrf_token %}
- {{form}}
+ {{form.as_p}}
</div>
- <input type="submit" value="Submit" class="btn btn-success">
+ <input type="submit" value="Submit" class="btn btn-success btn-lg">
</form>
</div>
{% endif %}
<br>
{% if comments %}
{% for comment in comments %}
- <div class="card mb-2">
+ <div class="card mb-2 col-md-8">
<div class="card-body p-3">
<div class="row mb-3">
<div class="col-6">
diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py
index 57ec7dd..a3cd3f1 100644
--- a/yaksh/templatetags/custom_filters.py
+++ b/yaksh/templatetags/custom_filters.py
@@ -3,6 +3,7 @@ from django.template.defaultfilters import stringfilter
from django.forms.fields import CheckboxInput
from ast import literal_eval
import os
+import pandas as pd
try:
from itertools import zip_longest
except ImportError:
@@ -192,4 +193,10 @@ def has_lesson_video(lesson_id):
status = True if lesson.first().video_path else False
else:
status = False
- return status \ No newline at end of file
+ return status
+
+
+@register.simple_tag
+def get_tc_percent(tc_id, data):
+ return data.get(str(tc_id), 0)
+
diff --git a/yaksh/test_models.py b/yaksh/test_models.py
index 67da7d1..fe0d3b5 100644
--- a/yaksh/test_models.py
+++ b/yaksh/test_models.py
@@ -1788,20 +1788,7 @@ class AnswerPaperTestCases(unittest.TestCase):
""" Test get_question_answer() method of Answer Paper"""
questions = self.answerpaper.questions.all()
answered = self.answerpaper.get_question_answers()
- for question in questions:
- answers_saved = Answer.objects.filter(question=question)
- error_list = [json.loads(ans.error) for ans in answers_saved]
- if answers_saved:
- self.assertGreater(len(answered[question]), len(answers_saved))
- ans = []
- err = []
- for val in answered[question]:
- if val.get('answer') is not None:
- ans.append(val.get('answer'))
- if val.get('error_list') is not None:
- err.append(val.get('error_list'))
- self.assertEqual(set(ans), set(answers_saved))
- self.assertEqual(error_list, err)
+ self.assertEqual(list(questions), list(answered.keys()))
def test_is_answer_correct(self):
self.assertTrue(self.answerpaper.is_answer_correct(self.questions[0]))
diff --git a/yaksh/test_views.py b/yaksh/test_views.py
index e87686c..3443c36 100644
--- a/yaksh/test_views.py
+++ b/yaksh/test_views.py
@@ -6912,20 +6912,6 @@ class TestLessons(TestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["msg"], err_msg)
- def test_preview_lesson_description(self):
- """ Test preview lesson description converted from md to html"""
- self.client.login(
- username=self.teacher.username,
- password=self.teacher_plaintext_pass
- )
- lesson = json.dumps({'description': self.lesson.description})
- response = self.client.post(
- reverse('yaksh:preview_html_text'),
- data=lesson, content_type="application/json"
- )
- self.assertEqual(response.status_code, 200)
- self.assertEqual(response.json()['data'], '<p>test description</p>')
-
class TestPost(TestCase):
def setUp(self):
@@ -8379,6 +8365,29 @@ class TestLessonContents(TestCase):
'integertestcase_set-0-type': 'integertestcase',
'integertestcase_set-0-correct': "1"}
)
+ self.client.post(
+ reverse('yaksh:add_marker_quiz',
+ kwargs={"content_type": '3',
+ "course_id": self.user1_course1.id,
+ "lesson_id": self.lesson1.id}),
+ data={'timer': '00:00:00', 'summary': 'Mcc_Lesson_stats',
+ 'description': 'My lesson question description',
+ 'language': 'other', 'type': 'mcc', 'topic': 'test',
+ 'points': '1', 'form-TOTAL_FORMS': 2,
+ 'form-MAX_NUM_FORMS': '',
+ 'form-INITIAL_FORMS': 0,
+ 'mcqtestcase_set-TOTAL_FORMS': 2,
+ 'mcqtestcase_set-INITIAL_FORMS': 0,
+ 'mcqtestcase_set-MIN_NUM_FORMS': 0,
+ 'mcqtestcase_set-MAX_NUM_FORMS': 0,
+ 'mcqtestcase_set-0-type': 'mcqtestcase',
+ 'mcqtestcase_set-0-options': "1",
+ 'mcqtestcase_set-0-correct': True,
+ 'mcqtestcase_set-1-type': 'mcqtestcase',
+ 'mcqtestcase_set-1-options': "2",
+ 'mcqtestcase_set-1-correct': False
+ }
+ )
que = Question.objects.filter(summary="My_Lesson_question")
single_que = que.first()
@@ -8431,6 +8440,43 @@ class TestLessonContents(TestCase):
)
self.assertEqual(student_info.get("student_id"), self.student.id)
+ # Test for mcc lesson question statistics
+ # Given
+ que = Question.objects.filter(summary="Mcc_Lesson_stats")
+
+ single_que = que.first()
+ toc = TableOfContents.objects.get(
+ course_id=self.user1_course1.id, lesson_id=self.lesson1.id,
+ object_id=single_que.id
+ )
+ self.client.logout()
+
+ self.client.login(
+ username=self.student.username,
+ password=self.student_plaintext_pass
+ )
+ response = self.client.post(
+ reverse('yaksh:submit_marker_quiz',
+ kwargs={"course_id": self.user1_course1.id,
+ "toc_id": toc.id}),
+ data={'answer': [str(i.id) for i in single_que.get_test_cases()]}
+ )
+ self.client.logout()
+
+ # Then
+ self.client.login(
+ username=self.user1.username,
+ password=self.user1_plaintext_pass
+ )
+ response = self.client.get(
+ reverse('yaksh:lesson_statistics',
+ kwargs={"course_id": self.user1_course1.id,
+ "lesson_id": self.lesson1.id,
+ "toc_id": toc.id})
+ )
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(student_info.get("student_id"), self.student.id)
+
def test_multiple_lesson_question_types(self):
self.client.login(
username=self.user1.username,
diff --git a/yaksh/urls.py b/yaksh/urls.py
index e716404..e93d80a 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -199,8 +199,6 @@ urlpatterns = [
views.design_module, name="design_module"),
url(r'^manage/courses/designmodule/(?P<module_id>\d+)/'
'(?P<course_id>\d+)/$', views.design_module, name="design_module"),
- url(r'^manage/courses/lesson/preview/$',
- views.preview_html_text, name="preview_html_text"),
url(r'^manage/courses/add_module/(?P<course_id>\d+)/$',
views.add_module, name="add_module"),
url(r'^manage/courses/add_module/(?P<course_id>\d+)/(?P<module_id>\d+)/$',
diff --git a/yaksh/views.py b/yaksh/views.py
index 7a4810c..dd9090d 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -3000,19 +3000,6 @@ def add_module(request, course_id=None, module_id=None):
@login_required
@email_verified
-def preview_html_text(request):
- user = request.user
- if not is_moderator(user):
- raise Http404('You are not allowed to view this page!')
- response_kwargs = {}
- response_kwargs['content_type'] = 'application/json'
- request_data = json.loads(request.body.decode("utf-8"))
- html_text = get_html_text(request_data['description'])
- return HttpResponse(json.dumps({"data": html_text}), **response_kwargs)
-
-
-@login_required
-@email_verified
def get_next_unit(request, course_id, module_id, current_unit_id=None,
first_unit=None):
user = request.user
@@ -4038,8 +4025,19 @@ def lesson_statistics(request, course_id, lesson_id, toc_id=None):
context['course_id'] = course_id
if toc_id:
per_que_data = TableOfContents.objects.get_question_stats(toc_id)
- paginator = Paginator(per_que_data[1], 50)
- context['question'] = per_que_data[0]
+ question = per_que_data[0]
+ answers = per_que_data[1]
+ is_percent_reqd = (
+ True if question.type == "mcq" or question.type == "mcc"
+ else False
+ )
+ per_tc_ans, total_count = TableOfContents.objects.get_per_tc_ans(
+ toc_id, question.type, is_percent_reqd
+ )
+ context['per_tc_ans'] = per_tc_ans
+ context['total_count'] = total_count
+ paginator = Paginator(answers, 50)
+ context['question'] = question
page = request.GET.get('page')
per_que_data = paginator.get_page(page)
context['is_que_data'] = True