commit
3e4ca8155e
18 changed files with 482 additions and 3 deletions
@ -0,0 +1,16 @@ |
|||||||
|
from django.http import HttpResponseForbidden |
||||||
|
|
||||||
|
|
||||||
|
class CheckPerm(object): |
||||||
|
@staticmethod |
||||||
|
def process_request(request): |
||||||
|
if '/admin' in request.path or "/management" in request.path \ |
||||||
|
or '/analytics' in request.path: |
||||||
|
|
||||||
|
if not request.user.is_authenticated(): |
||||||
|
return HttpResponseForbidden() |
||||||
|
|
||||||
|
if not (request.user.in_role == "M" or request.user.in_role == "S" |
||||||
|
or request.user.in_role == "A" or request.user.is_admin): |
||||||
|
|
||||||
|
return HttpResponseForbidden() |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
from django.conf.urls import url |
||||||
|
from analytics import views |
||||||
|
|
||||||
|
urlpatterns = [ |
||||||
|
url(r'^$', views.index_view), |
||||||
|
url(r'^theme/$', views.index_view_access_theme), |
||||||
|
url(r'^theme/new/$', views.new_view_access_theme), |
||||||
|
url(r'^homework/$', views.index_view_homework_wait), |
||||||
|
url(r'^homework/new/$', views.new_view_homework_wait), |
||||||
|
] |
||||||
@ -0,0 +1,155 @@ |
|||||||
|
from django.shortcuts import render_to_response, redirect, render |
||||||
|
import time, os, csv |
||||||
|
from datetime import date |
||||||
|
|
||||||
|
from lms.settings import MEDIA_ROOT |
||||||
|
|
||||||
|
from courses.models import Course, CourseTheme, Homework, Exam |
||||||
|
from journals.models import CourseThemeJ, HomeworkTry, ExamTry |
||||||
|
|
||||||
|
index_view = lambda request: render_to_response('analytics/index.html') |
||||||
|
|
||||||
|
|
||||||
|
def index_view_decor(url): |
||||||
|
def wrap(func): |
||||||
|
def get_request(request): |
||||||
|
start = request.GET.get('start', '') |
||||||
|
end = request.GET.get('end', '') |
||||||
|
|
||||||
|
path = MEDIA_ROOT + url + 's' + start + 'e' + end + 'progress.csv' |
||||||
|
|
||||||
|
try: |
||||||
|
with open(path, newline='') as file: |
||||||
|
reader = csv.reader(file, delimiter=',', quotechar='|') |
||||||
|
max = 0 |
||||||
|
res = [] |
||||||
|
for row in reader: |
||||||
|
max = max if max > len(row) else len(row) |
||||||
|
res1 = [] |
||||||
|
for i in row: |
||||||
|
k = i.split("$-$") |
||||||
|
k = {'value': k[0], 'background': 'none'}\ |
||||||
|
if len(i.split("$-$")) == 1 else {'value': k[0],'background': k[1]} |
||||||
|
res1.append(k) |
||||||
|
|
||||||
|
res.append(res1) |
||||||
|
for i in res: |
||||||
|
for j in range(max - len(i)): |
||||||
|
i.append({'value': 0, 'background': 'none'}) |
||||||
|
first = ['Курсы'] |
||||||
|
for i in range(max - 1): |
||||||
|
first.append("Тема " + str(i + 1)) |
||||||
|
except FileNotFoundError: |
||||||
|
return redirect(url + "new/?start=" + start + "&end=" + end) |
||||||
|
|
||||||
|
date_create = time.ctime(os.stat(path).st_atime) |
||||||
|
|
||||||
|
context = { |
||||||
|
'body': res, |
||||||
|
'header': first, |
||||||
|
'date_create': date_create, |
||||||
|
'start': start, |
||||||
|
'end': end, |
||||||
|
'url': url, |
||||||
|
} |
||||||
|
|
||||||
|
context.update(func()) |
||||||
|
|
||||||
|
return render(request, url[1:-1] + '.html', context=context) |
||||||
|
|
||||||
|
return get_request |
||||||
|
|
||||||
|
return wrap |
||||||
|
|
||||||
|
|
||||||
|
@index_view_decor("/analytics/theme/") |
||||||
|
def index_view_access_theme(): |
||||||
|
return {} |
||||||
|
|
||||||
|
|
||||||
|
@index_view_decor("/analytics/homework/") |
||||||
|
def index_view_homework_wait(): |
||||||
|
return {} |
||||||
|
|
||||||
|
|
||||||
|
def new_view_decor(url): |
||||||
|
def wrap(func): |
||||||
|
def get_request(request): |
||||||
|
start = request.GET.get('start', '') |
||||||
|
end = request.GET.get('end', '') |
||||||
|
|
||||||
|
path = MEDIA_ROOT + url + 's' + start + 'e' + end + 'progress.csv' |
||||||
|
|
||||||
|
start_date = None |
||||||
|
end_date = None |
||||||
|
|
||||||
|
try: |
||||||
|
start_date = date(*[int(i) for i in start.split('-')]) |
||||||
|
end_date = date(*[int(i) for i in end.split('-')]) |
||||||
|
except ValueError: |
||||||
|
pass |
||||||
|
|
||||||
|
if not check_date_validate(start_date, end_date): |
||||||
|
return redirect(url) |
||||||
|
|
||||||
|
try: |
||||||
|
with open(path, 'w', newline='') as csvfile: |
||||||
|
func(end_date, start_date, csvfile) |
||||||
|
return redirect(url + "?start=" + start + "&end=" + end) |
||||||
|
|
||||||
|
except FileNotFoundError: |
||||||
|
os.makedirs(MEDIA_ROOT + url) |
||||||
|
return redirect(url + "new/?start=" + start + "&end=" + end) |
||||||
|
|
||||||
|
return get_request |
||||||
|
|
||||||
|
return wrap |
||||||
|
|
||||||
|
|
||||||
|
@new_view_decor("/analytics/theme/") |
||||||
|
def new_view_access_theme(end_date, start_date, csvfile): |
||||||
|
for course in Course.objects.order_by('sort'): |
||||||
|
list = [course.title] |
||||||
|
for i in CourseTheme.objects.filter(course=course): |
||||||
|
kwargs = { |
||||||
|
'material': i, |
||||||
|
'success': True, |
||||||
|
} |
||||||
|
if end_date: |
||||||
|
kwargs['student__last_time__lte'] = end_date |
||||||
|
if start_date: |
||||||
|
kwargs['student__last_time__gte'] = start_date |
||||||
|
list.append(str(len(CourseThemeJ.objects.filter(**kwargs))) + ( |
||||||
|
"$-$yellow" if i._type == 'Ex' else "")) |
||||||
|
writercsv = csv.writer(csvfile, delimiter=',', quotechar='|') |
||||||
|
writercsv.writerow(list) |
||||||
|
|
||||||
|
|
||||||
|
@new_view_decor("/analytics/homework/") |
||||||
|
def new_view_homework_wait(end_date, start_date, csvfile): |
||||||
|
for course in Course.objects.order_by('sort'): |
||||||
|
list = [course.title] |
||||||
|
for i in CourseTheme.objects.filter(course=course): |
||||||
|
kwargs = { |
||||||
|
'success': False, |
||||||
|
'expired': False, |
||||||
|
'f_date': None |
||||||
|
} |
||||||
|
if end_date: |
||||||
|
kwargs['student__last_time__lte'] = end_date |
||||||
|
if start_date: |
||||||
|
kwargs['student__last_time__gte'] = start_date |
||||||
|
list.append(str( |
||||||
|
len(HomeworkTry.objects.filter(material=Homework.objects.filter(theme=i), **kwargs)) + |
||||||
|
len(ExamTry.objects.filter(material=Exam.objects.filter(theme=i), **kwargs)) |
||||||
|
)) |
||||||
|
writercsv = csv.writer(csvfile, delimiter=',', quotechar='|') |
||||||
|
writercsv.writerow(list) |
||||||
|
|
||||||
|
|
||||||
|
def check_date_validate(start=None, end=None): |
||||||
|
if start: |
||||||
|
if end: |
||||||
|
return (start < end) and (end < date.today()) |
||||||
|
return start < date.today() |
||||||
|
return end < date.today() if end else True |
||||||
|
unable to load file from base commit
|
|
unable to load file from base commit
|
|
unable to load file from base commit
|
|
unable to load file from base commit
|
|
unable to load file from base commit
|
|
unable to load file from base commit
|
@ -0,0 +1,41 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<title>Аналитика</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h2>Дата создания отчёта {{ date_create }}</h2> |
||||||
|
<button><a href="new?start={{ start }}&end={{ end }}">Сгенирировать отчёт</a></button> |
||||||
|
<button style="margin-bottom: 20px"><a href="/media{{ url }}s{{ start }}e{{ end }}progress.csv">Скачать отчёт</a></button> |
||||||
|
<button><a href="/analytics">На главную</a></button> |
||||||
|
<form action=""> |
||||||
|
<label>от</label> |
||||||
|
<input name="start" type="date" value="{{ start }}"> |
||||||
|
<label>до</label> |
||||||
|
<input name="end" type="date" value="{{ end }}"> |
||||||
|
<button type="submit">Подготовить отчёт</button> |
||||||
|
</form> |
||||||
|
|
||||||
|
<table border="1px"> |
||||||
|
<tr> |
||||||
|
{% for i in header %} |
||||||
|
<th>{{ i }}</th> |
||||||
|
{% endfor %} |
||||||
|
</tr> |
||||||
|
{% for i in body %} |
||||||
|
<tr> |
||||||
|
{% for j in i %} |
||||||
|
<td style="background: {{j.background}}">{{ j.value }}</td> |
||||||
|
{% endfor %} |
||||||
|
</tr> |
||||||
|
{% endfor %} |
||||||
|
</table> |
||||||
|
<p> |
||||||
|
{% block description %}{% endblock %} |
||||||
|
</p> |
||||||
|
|
||||||
|
<h2>Внимание! Новый отчёт генерируется 1 раз! Следите за записью в хедоре страницы, если вы нуждаетесь в обновлении <br> |
||||||
|
данных жмите кнопку "Сгенерировать отчёт" таким образом вы получите обновлённые данные для заданных пораметров фильтрации</h2> |
||||||
|
</body> |
||||||
|
</html> |
||||||
@ -0,0 +1,2 @@ |
|||||||
|
{% extends 'analytics/base.html' %} |
||||||
|
{% block description %}{% endblock %} |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<title>Аналитика</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h2>Меню поиска</h2> |
||||||
|
<h4><a href="theme">Студентов успешно прошедших тему</a></h4> |
||||||
|
<h4><a href="homework">Студентов ожидающих проверки домашки</a></h4> |
||||||
|
</body> |
||||||
|
</html> |
||||||
@ -0,0 +1,9 @@ |
|||||||
|
{% extends 'analytics/base.html' %} |
||||||
|
{% block description %} |
||||||
|
В данной таблице представлены данные о том, сколько студентов прошло заданную тему. <br> |
||||||
|
Темы не всегда проходятся последовательно, поэтому порой тему с большим порядковым номером прошло большее количество пользовавтелей. <br> |
||||||
|
Вы можите выставить фильтр по последней акутивности пользователя, фильтр может быть ограничивающим с одной стороны или может отсутствовать, <br> |
||||||
|
в случае ввода невалидных данных ошибки не происходит вас просто перенапровляет на начальную страницу. <br> |
||||||
|
Вы можите скачать отчёт в формате csv метка $-$yellow говорит о том что в данной теме есть экзамен,<br> |
||||||
|
в таблице темы содержашие экзамен подсвечены жёлтым светом |
||||||
|
{% endblock %} |
||||||
Loading…
Reference in new issue