diff --git a/stats.py b/stats.py index 3dc16a22e57e2d938dddcc69490474835365114d..7fa11869bd7890913b0a1faa012b305a54e26c42 100644 --- a/stats.py +++ b/stats.py @@ -8,20 +8,30 @@ from jobs import date_json_handler def stats(): return render_template('stats.html') - statsqueries = {} -statsqueries['course_count'] = "SELECT count(id) as count, semester FROM courses GROUP BY semester;" -statsqueries['lectures_count'] = "SELECT count(lectures.id) as count, semester FROM lectures JOIN courses on courses.id=lectures.course_id GROUP BY semester;" +statsqueries['formats_views'] = "SELECT formats.description AS x, count(log.id) AS y FROM log JOIN videos ON (videos.id = log.obj_id) JOIN formats ON (formats.id = videos.video_format) GROUP BY formats.id" +statsqueries['course_count'] = "SELECT semester AS x, count(id) AS y FROM courses GROUP BY semester" +statsqueries['lectures_count'] = "SELECT semester AS x, count(lectures.id) AS y FROM lectures JOIN courses ON (courses.id = lectures.course_id) GROUP BY semester" +statsqueries['categories_courses'] = "SELECT courses.subject AS x, count(courses.id) AS y FROM courses GROUP BY courses.subject ORDER BY y DESC LIMIT 100" +statsqueries['organizer_courses'] = "SELECT courses.organizer AS x, count(courses.id) AS y FROM courses GROUP BY courses.organizer ORDER BY y DESC LIMIT 100" +statsqueries['categories_lectures'] = "SELECT courses.subject AS x, count(lectures.id) AS y FROM lectures JOIN courses ON (courses.id = lectures.course_id) GROUP BY courses.subject ORDER BY y DESC LIMIT 100" +statsqueries['lecture_views'] = "SELECT lectures.time AS x, count(log.id) AS y FROM log JOIN videos ON (videos.id = log.obj_id) JOIN lectures ON (lectures.id = videos.lecture_id) WHERE (lectures.course_id = ?) GROUP BY lectures.id ORDER BY lectures.time" + +def plotly_date_handler(obj): + return obj.strftime("%Y-%m-%d %H:%M:%S") -@app.route('/stats/data/<dataname>') -@app.route('/stats/data/<dataname>/<parameter>') +@app.route('/stats/generic/<req>') +@app.route('/stats/generic/<req>/<param>') @mod_required -def stats_data(dataname, parameter=None): - if parameter: - data = query(statsqueries[dataname],parameter) - else: - data = query(statsqueries[dataname]) - return Response(json.dumps(data, default=date_json_handler), mimetype='application/json') +def stats_generic(req, param=None): + if req not in statsqueries: + return 404, 'Not found' + rows = query(statsqueries[req], *(statsqueries[req].count('?')*[param])) + res = {'x':[], 'y':[]} + for row in rows: + res['x'].append(row['x']) + res['y'].append(row['y']) + return Response(json.dumps(res, default=plotly_date_handler), mimetype='application/json') @app.route('/stats/viewsperday') def stats_viewsperday(): @@ -30,7 +40,6 @@ def stats_viewsperday(): courseid = request.args.get('course', None) lectureid = request.args.get('lecture', None) videoid = request.args.get('video', None) - print(start, end, courseid, lectureid, videoid) rows = query('''SELECT log.id AS id, log.time AS time, formats.description AS fmt FROM log JOIN videos ON (videos.id = log.obj_id) diff --git a/templates/course.html b/templates/course.html index 20f00cdbb8ae499b64daa5d1d6529b053c752e9f..5cb4f7c2a34ee119b51d8c68bdbfe4a5cc8b3159 100644 --- a/templates/course.html +++ b/templates/course.html @@ -4,7 +4,7 @@ {% from 'macros.html' import moderator_checkbox %} {% from 'macros.html' import preview %} {% from 'macros.html' import moderator_permissioneditor %} -{% from 'macros.html' import stats_viewsperday %} +{% from 'macros.html' import stats_viewsperday, stats_generic %} {% extends "base.html" %} {% block title %}- {{course.title}}{% endblock %} @@ -47,8 +47,10 @@ </tbody> </table> </div> - <div id="statview" class="col-xs-11" style="height:600px"></div> + <div id="statview" class="col-xs-6" style="height:600px"></div> {{stats_viewsperday("statview", "Abrufe pro Tag", course=course.id)}} + <div id="lecture_views" class="col-xs-6" style="height:600px"></div> + {{stats_generic("lecture_views", "lecture_views", "Abrufe pro Aufnahme", param=course.id, type="bar")}} {% endif %} </div> </div> diff --git a/templates/macros.html b/templates/macros.html index 676abdbc5c124a51832096014e51fa6cf9d162e5..757ce315f952345bd457225e2abc80ff54be2900 100644 --- a/templates/macros.html +++ b/templates/macros.html @@ -255,12 +255,11 @@ $('#embedcodebtn').popover( error: moderator.api.handleapierror, success: function (data) { var traces = []; - var i = 0; - if (data.views.length == 2) - i = 1; - for (; i < data.views.length; i++) { - traces.push({"x": data.times, "y": data.views[i].vals, "type": "{{type}}", "name": data.views[i].name}); + for (var i = 1; i < data.views.length; i++) { + traces.push({"x": data.times, "y": data.views[i].vals, "type": "{{type}}", "name": data.views[i].name, line: {"width": 1}}); } + if (data.views.length > 2) + traces.push({"x": data.times, "y": data.views[0].vals, "type": "{{type}}", "name": "gesamt", line: {"color": "black", "width": 2}}); var layout = { "title": "{{title}}", "showlegend": (traces.length != 1) @@ -270,3 +269,39 @@ $('#embedcodebtn').popover( }); </script> {% endmacro %} + +{% macro stats_generic(id, req, title, param=None, type="scatter") %} +<script> + $.ajax({ + method: "GET", + url: "{{url_for('stats_generic', req=req, param=param)}}", + dataType: "json", + error: moderator.api.handleapierror, + success: function (data) { + var layout = { + "title": "{{title}}", + "showlegend": false + }; + Plotly.newPlot("{{id}}", [{"x": data.x, "y": data.y, "type": "{{type}}"}], layout, { "modeBarButtonsToRemove": ['sendDataToCloud','hoverCompareCartesian'], "displaylogo": false}); + } + }); +</script> +{% endmacro %} + +{% macro stats_pie(id, req, title, showlegend=True, param=None) %} +<script> + $.ajax({ + method: "GET", + url: "{{url_for('stats_generic', req=req, param=param)}}", + dataType: "json", + error: moderator.api.handleapierror, + success: function (data) { + var layout = { + "title": "{{title}}", + "showlegend": {% if showledgend %}true{% else %}false{% endif %} + }; + Plotly.newPlot("{{id}}", [{"labels": data.x, "values": data.y, "type": "pie"}], layout, { "modeBarButtonsToRemove": ['sendDataToCloud','hoverCompareCartesian'], "displaylogo": false}); + } + }); +</script> +{% endmacro %} diff --git a/templates/stats.html b/templates/stats.html index 60ebc4a6f92795b476975e54c96587e38a0e8606..b96585a0cfb951d0251ff3de41e6762ecb1d6337 100644 --- a/templates/stats.html +++ b/templates/stats.html @@ -1,4 +1,4 @@ -{% from 'macros.html' import stats_viewsperday %} +{% from 'macros.html' import stats_viewsperday, stats_generic, stats_pie %} {% extends "base.html" %} {% block header %} @@ -14,52 +14,18 @@ </div> <div class="panel-body"> <div class="row col-xs-12"> - <div id="coursespersemester" style="height:600px;" class="col-xs-6" ></div> - <script> - $.ajax({ - method: "GET", - url: "/stats/data/course_count", - dataType: "json", - error: moderator.api.handleapierror, - success: function (data) { - var trace = {"y": [], "x": [], "type": "scatter"}; - for (var i=0; i < data.length; i++) { - if (data[i].semester != "") { - trace.x.push(data[i].semester) - trace.y.push(data[i].count) - } - } - var layout = { - "title": 'Veranstaltungen pro Semester', - "showlegend": false - }; - Plotly.newPlot('coursespersemester', [trace], layout, { "modeBarButtonsToRemove": ['sendDataToCloud','hoverCompareCartesian'], "displaylogo": false}); - } - }); - </script> - <div id="lecturespersemester" style="height:600px" class="col-xs-6"></div> - <script> - $.ajax({ - method: "GET", - url: "/stats/data/lectures_count", - dataType: "json", - error: moderator.api.handleapierror, - success: function (data) { - var trace = {"y": [], "x": [], "type": "scatter"}; - for (var i=0; i < data.length; i++) { - if (data[i].semester != "") { - trace.x.push(data[i].semester) - trace.y.push(data[i].count) - } - } - var layout = { - "title": 'Aufnahmen pro Semester', - "showlegend": false - }; - Plotly.newPlot('lecturespersemester', [trace], layout, { "modeBarButtonsToRemove": ['sendDataToCloud','hoverCompareCartesian'], "displaylogo": false}); - } - }); - </script> + <div id="course_count" class="col-xs-6" style="height:600px"></div> + {{stats_generic("course_count", "course_count", "Veranstaltungen pro Jahr")}} + <div id="lectures_count" class="col-xs-6" style="height:600px"></div> + {{stats_generic("lectures_count", "lectures_count", "Aufnahmen pro Jahr")}} + <div id="formats_views" class="col-xs-6" style="height:600px"></div> + {{stats_pie("formats_views", "formats_views", "Formatnutzung")}} + <div id="organizer_courses" class="col-xs-6" style="height:600px"></div> + {{stats_pie("organizer_courses", "organizer_courses", "Veranstaltungne nach Dozent", showlegend=False)}} + <div id="categories_courses" class="col-xs-6" style="height:600px"></div> + {{stats_pie("categories_courses", "categories_courses", "Veranstaltungen nach Kategorie", showlegend=False)}} + <div id="categories_lectures" class="col-xs-6" style="height:600px"></div> + {{stats_pie("categories_lectures", "categories_lectures", "Aufnahmen nach Kategorie", showlegend=False)}} <div id="statview" class="col-xs-12" style="height:600px"></div> {{stats_viewsperday("statview", "Abrufe pro Tag")}} </div>