summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--stats/models.py16
-rw-r--r--stats/templates/view_lesson_tracking.html39
-rw-r--r--yaksh/static/yaksh/js/show_toc.js26
-rw-r--r--yaksh/templates/yaksh/course_added_modules.html34
-rw-r--r--yaksh/templates/yaksh/courses.html20
-rw-r--r--yaksh/templates/yaksh/show_lesson_statistics.html41
-rw-r--r--yaksh/templates/yaksh/show_video.html2
-rw-r--r--yaksh/templatetags/custom_filters.py11
8 files changed, 139 insertions, 50 deletions
diff --git a/stats/models.py b/stats/models.py
index 0200a80..56c7f0d 100644
--- a/stats/models.py
+++ b/stats/models.py
@@ -1,7 +1,11 @@
+# Python Imports
+import pandas as pd
+
# Django Imports
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
+from django.db.models import F
# Local Imports
from yaksh.models import Course, Lesson
@@ -93,6 +97,18 @@ class TrackLesson(models.Model):
return str(timezone.timedelta(seconds=total_duration))
return self.get_current_time()
+ def get_no_of_vists(self):
+ lesson_logs = self.lessonlog_set.values("last_access_time").annotate(
+ visits=F('last_access_time')
+ )
+ df = pd.DataFrame(lesson_logs)
+ visits = 1
+ if not df.empty:
+ visits = df.groupby(
+ [df['visits'].dt.date]
+ ).first().count()['visits']
+ return visits
+
def __str__(self):
return (f"Track {self.lesson} in {self.course} "
f"for {self.user.get_full_name()}")
diff --git a/stats/templates/view_lesson_tracking.html b/stats/templates/view_lesson_tracking.html
index ef5c9ae..d8d35c2 100644
--- a/stats/templates/view_lesson_tracking.html
+++ b/stats/templates/view_lesson_tracking.html
@@ -5,26 +5,29 @@
<script type="text/javascript" src="{% static 'yaksh/js/jquery.tablesorter.min.js' %}">
</script>
<script type="text/javascript">
- function get_time_in_seconds(time) {
- var time = time.split(":");
- var hh = parseInt(time[0]);
- var mm = parseInt(time[1]);
- var ss = parseInt(time[2]);
- return hh * 3600 + mm * 60 + ss;
- }
-
$(document).ready(function() {
- $("#stats-table").tablesorter({});
+ $.tablesorter.addWidget({
+ id: "numbering",
+ format: function(table) {
+ var c = table.config;
+ $("tr:visible", table.tBodies[0]).each(function(i) {
+ $(this).find('td').eq(0).text(i + 1);
+ });
+ }
+ });
+ $("#stats-table").tablesorter({
+ headers: {0: { sorter: false }}, widgets: ['numbering']
+ });
});
</script>
{% endblock %}
{% block content %}
-<div class="container">
+<div class="container-fluid">
{% with objects.object_list as trackings %}
<center>
<h3>Statistics for {% with trackings|first as entry %} {{entry.lesson}} {% endwith %}</h3>
</center>
- <a class="btn btn-primary" href="{% url 'yaksh:lesson_statistics' course_id lesson_id %}">
+ <a class="btn btn-primary" href="{% url 'yaksh:get_course_modules' course_id %}">
<i class="fa fa-arrow-left"></i>&nbsp;Back
</a>
<br><br>
@@ -43,19 +46,29 @@
<th>Percentage Watched&nbsp;<i class="fa fa-sort"></i></th>
<th>Watched Once Completely&nbsp;<i class="fa fa-sort"></i></th>
<th>Total Time Spent&nbsp;<i class="fa fa-sort"></i></th>
+ <th>Total Visits&nbsp;<i class="fa fa-sort"></i></th>
</tr>
</thead>
{% for track in trackings %}
<tr>
- <td>{{ forloop.counter0|add:objects.start_index }}</td>
+ <td>{{ forloop.counter0 }}</td>
<td>{{track.user.get_full_name}}</td>
<td>{{track.get_last_access_time}}</td>
<td>{{track.creation_time}}</td>
<td>{{track.get_current_time}}</td>
<td>{{track.get_video_duration}}</td>
<td>{{track.get_percentage_complete}}</td>
- <td>{{track.get_watched}}</td>
+ <td>
+ {% with track.get_watched as watched %}
+ {% if watched %}
+ <span class="badge-pill badge-success">{{watched}}</span>
+ {% else %}
+ <span class="badge-pill badge-success">{{watched}}</span>
+ {% endif %}
+ {% endwith %}
+ </td>
<td>{{track.time_spent}}</td>
+ <td>{{track.get_no_of_vists}}</td>
</tr>
{% endfor %}
</table>
diff --git a/yaksh/static/yaksh/js/show_toc.js b/yaksh/static/yaksh/js/show_toc.js
index 914ab1c..2bedc6a 100644
--- a/yaksh/static/yaksh/js/show_toc.js
+++ b/yaksh/static/yaksh/js/show_toc.js
@@ -27,10 +27,8 @@ $(document).ready(function() {
var total_duration;
player.on('ready loadedmetadata', event => {
total_duration = parseInt(player.duration);
+ store_tracker_time(total_duration);
$("#video_duration").val(get_time_in_hrs(total_duration));
- if (total_duration > 0) {
- start_tracker((total_duration * 1000) / 4, player);
- }
});
player.on('timeupdate', event => {
@@ -44,10 +42,17 @@ $(document).ready(function() {
}
else {
if(player.fullscreen.active) player.fullscreen.exit();
+ player.pause()
url = $("#toc_"+content.id).val();
ajax_call(url, "GET", screen_lock=true);
}
}
+ if(markers.length > 0 && current_time >= markers[track_count]) {
+ track_count++;
+ var csrf = document.getElementById("track-form").elements[0].value;
+ ajax_call($("#track-form").attr("action"), $("#track-form").attr("method"),
+ $("#track-form").serialize(), csrf, screen_lock=false);
+ }
});
player.on('ended', event => {
var csrf = document.getElementById("track-form").elements[0].value;
@@ -57,16 +62,11 @@ $(document).ready(function() {
});
});
-
-function start_tracker(slice_duration, player) {
- setTimeout(function run() {
- if(player && player.playing) {
- var csrf = document.getElementById("track-form").elements[0].value;
- ajax_call($("#track-form").attr("action"), $("#track-form").attr("method"),
- $("#track-form").serialize(), csrf, screen_lock=false);
- }
- setTimeout(run, slice_duration);
- }, slice_duration);
+function store_tracker_time(duration) {
+ marker = duration / 4;
+ for(var i = marker; i <= duration - marker; i = i + marker) {
+ markers.push(i);
+ }
}
function show_topic(description, override) {
diff --git a/yaksh/templates/yaksh/course_added_modules.html b/yaksh/templates/yaksh/course_added_modules.html
index d420b95..80d87c0 100644
--- a/yaksh/templates/yaksh/course_added_modules.html
+++ b/yaksh/templates/yaksh/course_added_modules.html
@@ -1,3 +1,4 @@
+{% load custom_filters %}
{% if is_modules %}
{% block pagetitle %} <center> <h3>Course Modules</h3> </center> {% endblock %}
<a href="{% url 'yaksh:add_module' course.id %}" class="btn btn-primary btn-lg">
@@ -49,7 +50,8 @@
<table class="table table-responsive-sm">
{% for unit in units %}
<tr>
- <td>
+ <td>{{forloop.counter}}</td>
+ <td width="25%">
{% if unit.type == "quiz" %}
{% if unit.quiz.is_exercise %}
<a href="{% url 'yaksh:edit_exercise' course.id module.id unit.quiz.id %}">
@@ -69,12 +71,12 @@
{% if quiz.questionpaper_set.get.id %}
<a href="{% url 'yaksh:designquestionpaper' course.id quiz.id quiz.questionpaper_set.get.id %}" class="btn btn-primary">
<i class="fa fa-edit"></i>
- Edit Question Paper
+ Question Paper
</a>
{% else %}
<a href="{% url 'yaksh:designquestionpaper' course.id quiz.id %}" class="btn btn-success">
<i class="fa fa-plus-circle"></i>
- Add Question Paper
+ Question Paper
</a>
{% endif %}
{% endwith %}
@@ -95,6 +97,14 @@
</td>
<td>
{% if unit.type == "quiz" %}
+ ----
+ {% else %}
+ {% get_lesson_views course.id unit.lesson.id as views %}
+ {{views.0}} views out of {{views.1}}
+ {% endif %}
+ </td>
+ <td>
+ {% if unit.type == "quiz" %}
{% if unit.quiz.questionpaper_set.get.id %}
<a href="{% url 'yaksh:show_statistics' unit.quiz.questionpaper_set.get.id course.id %}" class="btn btn-outline-primary">
<i class="fa fa-line-chart"></i>
@@ -104,9 +114,23 @@
----
{% endif %}
{% else %}
- <a href="{% url 'yaksh:lesson_statistics' course.id unit.lesson.id %}" class="btn btn-outline-primary">
- <i class="fa fa-line-chart"></i>&nbsp;Statistics
+ <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
+ <button type="button" class="btn btn-outline-primary">
+ <i class="fa fa-line-chart"></i>
+ Statistics
+ </button>
+ <div class="btn-group" role="group">
+ <button id="btnGroupDrop1" type="button" class="btn btn-outline-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></button>
+ <div class="dropdown-menu" aria-labelledby="btnGroupDrop1" style="">
+ <a class="dropdown-item" href="{% url 'stats:view_lesson_watch_stats' course.id unit.lesson.id %}">
+ Video Views
+ </a>
+ <a class="dropdown-item" href="{% url 'yaksh:lesson_statistics' course.id unit.lesson.id %}">
+ Quiz Submissions
</a>
+ </div>
+ </div>
+ </div>
{% endif %}
</td>
</tr>
diff --git a/yaksh/templates/yaksh/courses.html b/yaksh/templates/yaksh/courses.html
index 151e1fb..38c106c 100644
--- a/yaksh/templates/yaksh/courses.html
+++ b/yaksh/templates/yaksh/courses.html
@@ -106,6 +106,17 @@
<div class="card border-primary">
<div class="card-header" style="height: 150px">
{{course.name}}
+ <div>
+ {% if user.id != course.creator.id %}
+ <span class="badge badge-pill badge-warning">
+ Allotted Course
+ </span>
+ {% else %}
+ <span class="badge badge-pill badge-primary">
+ Created Course
+ </span>
+ {% endif %}
+ </div>
</div>
<div class="card-body">
<div class="row">
@@ -119,15 +130,6 @@
</div>
<hr>
<div class="row">
- <div class="col-md-5">
- <span class="badge badge-pill badge-info">
- {% if user.id != course.creator.id %}
- Allotted Course
- {% else %}
- Created Course
- {% endif %}
- </span>
- </div>
<div class="col-md-3">
{% if course.active %}
<span class="badge badge-pill badge-success">
diff --git a/yaksh/templates/yaksh/show_lesson_statistics.html b/yaksh/templates/yaksh/show_lesson_statistics.html
index 0c35e40..a7c2ebd 100644
--- a/yaksh/templates/yaksh/show_lesson_statistics.html
+++ b/yaksh/templates/yaksh/show_lesson_statistics.html
@@ -1,7 +1,31 @@
{% extends "manage.html" %}
+{% load static %}
{% load custom_filters %}
{% block title %} Lesson Statistics {% endblock %}
{% block pagetitle %} Statistics for {{lesson}} {% endblock %}
+{% block script %}
+<script type="text/javascript" src="{% static 'yaksh/js/jquery.tablesorter.min.js' %}">
+</script>
+<script type="text/javascript">
+ $(document).ready(function() {
+ $.tablesorter.addWidget({
+ id: "numbering",
+ format: function(table) {
+ var c = table.config;
+ $("tr:visible", table.tBodies[0]).each(function(i) {
+ $(this).find('td').eq(0).text(i + 1);
+ });
+ }
+ });
+ $("#stats-table").tablesorter({
+ headers: {
+ 0: { sorter: false }
+ },
+ widgets: ['numbering']
+ });
+ });
+</script>
+{% endblock %}
{% block content %}
<div class="container-fluid">
<br>
@@ -11,11 +35,6 @@
<i class="fa fa-arrow-left"></i>&nbsp;Back
</a>
</div>
- <div class="col-md-4">
- <a class="btn btn-outline-dark" href="{% url 'stats:view_lesson_watch_stats' course_id lesson.id %}">
- <i class="fa fa-line-chart"></i>&nbsp;Video Statistics
- </a>
- </div>
</div>
<br>
{% if data %}
@@ -161,16 +180,18 @@
<br><br>
{% endif %}
{% include "yaksh/paginator.html" %}
- <table class="table table-responsive">
+ <table class="table table-responsive" id="stats-table">
+ <thead>
<tr>
<th>Sr No.</th>
- <th>Student Name</th>
- <th>Email</th>
- <th>Latest Submission</th>
+ <th>Student Name&nbsp;<i class="fa fa-sort"></i></th>
+ <th>Email&nbsp;<i class="fa fa-sort"></i></th>
+ <th>Latest Submission&nbsp;<i class="fa fa-sort"></i></th>
</tr>
+ </thead>
{% for data in objects.object_list %}
<tr>
- <td>{{ forloop.counter0|add:objects.start_index }}</td>
+ <td>{{ forloop.counter }}</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 %}
diff --git a/yaksh/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html
index 0151f6b..b4f5628 100644
--- a/yaksh/templates/yaksh/show_video.html
+++ b/yaksh/templates/yaksh/show_video.html
@@ -9,6 +9,8 @@
var contents_by_time = JSON.parse('{{ contents_by_time|safe }}');
var loc = 0;
var video_time = [];
+ var markers = [];
+ var track_count = 0;
</script>
<script type="text/javascript" src="{% static 'yaksh/js/show_toc.js' %}">
</script>
diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py
index a3cd3f1..91681c2 100644
--- a/yaksh/templatetags/custom_filters.py
+++ b/yaksh/templatetags/custom_filters.py
@@ -11,7 +11,11 @@ except ImportError:
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
+
+# Local Imports
from yaksh.models import User, Course, Quiz, TableOfContents, Lesson
+from stats.models import TrackLesson
+
register = template.Library()
@@ -200,3 +204,10 @@ def has_lesson_video(lesson_id):
def get_tc_percent(tc_id, data):
return data.get(str(tc_id), 0)
+
+@register.simple_tag
+def get_lesson_views(course_id, lesson_id):
+ course = Course.objects.get(id=course_id)
+ return TrackLesson.objects.filter(
+ course_id=course_id, lesson_id=lesson_id
+ ).count(), course.students.count()