Commit 34817c0f312f39881f901daa0af9a273a7e6df91
Exists in
master
and in
2 other branches
Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring
Showing
12 changed files
with
293 additions
and
80 deletions
Show diff stats
analytics/static/.sass-cache/01cecb7b42e56765f6ed49ed3c70281ebdc742c7/general.sassc
No preview for this file type
analytics/static/analytics/general.css
@@ -47,8 +47,7 @@ | @@ -47,8 +47,7 @@ | ||
47 | color: #ffffff; } | 47 | color: #ffffff; } |
48 | 48 | ||
49 | .tag-name { | 49 | .tag-name { |
50 | - color: #ffffff; | ||
51 | - font-size: 10px; } | 50 | + color: #ffffff; } |
52 | 51 | ||
53 | #left-data-selector { | 52 | #left-data-selector { |
54 | background: linear-gradient(#0e8999, #6bf0ce); | 53 | background: linear-gradient(#0e8999, #6bf0ce); |
@@ -60,7 +59,8 @@ | @@ -60,7 +59,8 @@ | ||
60 | width: 30%; | 59 | width: 30%; |
61 | float: left; } | 60 | float: left; } |
62 | .chart h4 { | 61 | .chart h4 { |
63 | - color: #009688; } | 62 | + color: #009688; |
63 | + text-align: center; } | ||
64 | 64 | ||
65 | .selector { | 65 | .selector { |
66 | width: 90%; | 66 | width: 90%; |
@@ -115,4 +115,8 @@ | @@ -115,4 +115,8 @@ | ||
115 | .most-accessed-item:hover { | 115 | .most-accessed-item:hover { |
116 | background-color: #3aa7ad; } | 116 | background-color: #3aa7ad; } |
117 | 117 | ||
118 | +#month_selector_div { | ||
119 | + text-align: center; | ||
120 | + color: #009688; } | ||
121 | + | ||
118 | /*# sourceMappingURL=general.css.map */ | 122 | /*# sourceMappingURL=general.css.map */ |
analytics/static/analytics/general.css.map
1 | { | 1 | { |
2 | "version": 3, | 2 | "version": 3, |
3 | -"mappings": "AAEA,YAAY;EACR,MAAM,EAAE,iBAAiB;EACzB,aAAa,EAAE,IAAI;EACnB,OAAO,EAAE,IAAI;EACb,QAAQ,EAAE,IAAI;EACd,KAAK,EAAE,IAAI;EACX,gBAAgB,EAAE,OAAO;;AAE7B,sBAAsB;EAClB,MAAM,EAAE,GAAG;EACX,OAAO,EAAE,KAAK;EACd,yBAAE;IACE,KAAK,EAdC,OAAO;EAgBjB,yBAAE;IACE,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,WAAW;IACpB,KAAK,EAAE,GAAG;IACV,aAAa,EAAE,GAAG;IAElB,4BAAE;MACE,YAAY,EAAE,EAAE;MAChB,KAAK,EAAE,GAAG;MACV,KAAK,EAAE,KAAK;MACZ,SAAS,EAAE,IAAI;MACf,gBAAgB,EAAE,OAAO;MACzB,KAAK,EAAE,IAAI;MACX,UAAU,EAAE,MAAM;MAClB,aAAa,EAAE,IAAI;MACnB,MAAM,EAAE,IAAI;IAGhB,qCAAW;MACP,gBAAgB,EAAE,OAAO;MACzB,KAAK,EAAE,IAAI;MACX,UAAU,EAAE,MAAM;MAClB,aAAa,EAAE,IAAI;;AAM/B,sBAAsB;EAClB,UAAU,EAAE,2CAA2C;EACvD,MAAM,EAAE,IAAI;EACZ,aAAa,EAAE,IAAI;EACnB,KAAK,EAAE,OAAO;EACd,WAAW,EAAE,GAAG;EAChB,UAAU,EAAE,IAAI;EAEhB,yBAAE;IACE,WAAW,EAAE,EAAE;;AAGvB,UAAU;EACN,aAAa,EAAE,IAAI;EACnB,KAAK,EAAE,OAAO;;AAKlB,SAAS;EACL,KAAK,EAAE,OAAO;EACd,SAAS,EAAE,IAAI;;AAGnB,mBAAmB;EACf,UAAU,EAAE,iCAAmC;EAC/C,UAAU,EAAE,EAAE;EACd,WAAW,EAAE,EAAE;EACf,cAAc,EAAE,EAAE;;AAEtB,MAAM;EACF,KAAK,EAAE,GAAG;EACV,KAAK,EAAE,IAAI;EACX,SAAE;IACE,KAAK,EA9EC,OAAO;;AAgFrB,SAAS;EACL,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,KAAK;EACZ,YAAY,EAAE,GAAG;EACjB,gBAAgB,EAAE,OAAO;EACzB,UAAU,EAAE,GAAG;EACf,aAAa,EAAE,iBAAiB;EAChC,WAAC;IACG,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,IAAI;;AAInB,qBAAO;EACH,UAAU,EAAE,MAAM;;AAE1B,aAAa;EACT,UAAU,EAAE,iCAAkC;EAC9C,KAAK,EAAE,KAAK;EACZ,aAAa,EAAE,IAAI;EACnB,OAAO,EAAE,GAAG;;AAEhB,mBAAmB;EACf,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,GAAG;EACV,WAAW,EAAE,EAAE;EACf,UAAU,EAAE,EAAE;EACd,QAAQ,EAAE,QAAQ;EAClB,YAAY,EAAE,CAAC;EACf,KAAK,EAAE,KAAK;EACZ,MAAM,EAAE,iBAAiB;EACzB,UAAU,EAAE,sDAAsD;EAElE,sBAAE;IACE,YAAY,EAAE,EAAE;;AAExB,qDAAqD;EACjD,MAAM,EAAE,IAAI;EACZ,IAAI,EAAE,GAAG;EACT,MAAM,EAAE,iBAAiB;EACzB,OAAO,EAAE,GAAG;EACZ,MAAM,EAAE,CAAC;EACT,KAAK,EAAE,CAAC;EACR,QAAQ,EAAE,QAAQ;EAClB,cAAc,EAAE,IAAI;;AAGxB,0BAA0B;EACtB,YAAY,EAAE,IAAI;EAClB,WAAW,EAAE,IAAI;EACjB,YAAY,EAAE,sBAAsB;EACpC,mBAAmB,EAAE,OAAO;;AAEhC,yBAAyB;EACrB,gBAAgB,EAAE,OAAO", | 3 | +"mappings": "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", |
4 | "sources": ["general.sass"], | 4 | "sources": ["general.sass"], |
5 | "names": [], | 5 | "names": [], |
6 | "file": "general.css" | 6 | "file": "general.css" |
analytics/static/analytics/general.sass
@@ -63,7 +63,6 @@ $title-color: #009688 | @@ -63,7 +63,6 @@ $title-color: #009688 | ||
63 | 63 | ||
64 | .tag-name | 64 | .tag-name |
65 | color: #ffffff | 65 | color: #ffffff |
66 | - font-size: 10px | ||
67 | 66 | ||
68 | 67 | ||
69 | #left-data-selector | 68 | #left-data-selector |
@@ -75,8 +74,10 @@ $title-color: #009688 | @@ -75,8 +74,10 @@ $title-color: #009688 | ||
75 | .chart | 74 | .chart |
76 | width: 30% | 75 | width: 30% |
77 | float: left | 76 | float: left |
77 | + | ||
78 | h4 | 78 | h4 |
79 | color: $title-color | 79 | color: $title-color |
80 | + text-align: center | ||
80 | 81 | ||
81 | .selector | 82 | .selector |
82 | width: 90% | 83 | width: 90% |
@@ -133,4 +134,9 @@ $title-color: #009688 | @@ -133,4 +134,9 @@ $title-color: #009688 | ||
133 | border-bottom-color: #52b7bd | 134 | border-bottom-color: #52b7bd |
134 | 135 | ||
135 | .most-accessed-item:hover | 136 | .most-accessed-item:hover |
136 | - background-color: #3aa7ad | ||
137 | \ No newline at end of file | 137 | \ No newline at end of file |
138 | + background-color: #3aa7ad | ||
139 | + | ||
140 | + | ||
141 | +#month_selector_div | ||
142 | + text-align: center | ||
143 | + color: #009688 | ||
138 | \ No newline at end of file | 144 | \ No newline at end of file |
analytics/static/analytics/js/behavior.js
1 | 1 | ||
2 | + | ||
3 | + | ||
2 | $(document).ready(function(){ | 4 | $(document).ready(function(){ |
3 | selectors_options.init(); | 5 | selectors_options.init(); |
6 | + | ||
7 | + //for month selector | ||
8 | + | ||
9 | + $('#month_selector').change(function(){ | ||
10 | + $.get('/analytics/amount_active_users_per_day', {month: $(this).val() }).done(function(data){ | ||
11 | + charts.month_heatmap(data, '#right-chart-body'); | ||
12 | + | ||
13 | + }); | ||
14 | + }); | ||
15 | + //week date selector at the right-chart field | ||
16 | + $('input.datepicker').datetimepicker({ | ||
17 | + format: 'L', | ||
18 | + defaultDate: new Date(), | ||
19 | + }).on('dp.change', function(ev){ | ||
20 | + $.get('/analytics/get_days_of_the_week_log', {date: ev.date._i}).done(function(data){ | ||
21 | + charts.month_heatmap(data, '#bottom-right-chart-body'); | ||
22 | + }); | ||
23 | + | ||
24 | + }); | ||
25 | + | ||
26 | + | ||
27 | + | ||
28 | + | ||
4 | }); | 29 | }); |
5 | 30 | ||
6 | 31 | ||
32 | + | ||
7 | var selectors_options = { | 33 | var selectors_options = { |
8 | init: function(){ | 34 | init: function(){ |
9 | selectors = $("div.selector"); | 35 | selectors = $("div.selector"); |
@@ -66,3 +92,5 @@ var selectors_options = { | @@ -66,3 +92,5 @@ var selectors_options = { | ||
66 | $(e).removeAttr("opened"); //remove attribute so it can call API again | 92 | $(e).removeAttr("opened"); //remove attribute so it can call API again |
67 | }, | 93 | }, |
68 | }; | 94 | }; |
95 | + | ||
96 | + |
analytics/static/analytics/js/charts.js
@@ -348,27 +348,7 @@ var charts = { | @@ -348,27 +348,7 @@ var charts = { | ||
348 | var width = 800; | 348 | var width = 800; |
349 | var height = 300; | 349 | var height = 300; |
350 | 350 | ||
351 | - function min(){ | ||
352 | - minimum = 100000000000; | ||
353 | - for(var i = 0; i < dataset.length; i++){ | ||
354 | - if (dataset[i]['count'] < min){ | ||
355 | - minimum = dataset[i]['count']; | ||
356 | - } | ||
357 | - } | ||
358 | - | ||
359 | - return minimum | ||
360 | - } | ||
361 | - | ||
362 | - function max(){ | ||
363 | - maximum = 0; | ||
364 | - for(var i = 0; i < dataset.length; i++){ | ||
365 | - if (dataset[i]['count'] > max){ | ||
366 | - maximum = dataset[i]['count']; | ||
367 | - } | ||
368 | - } | ||
369 | - | ||
370 | - return maximum | ||
371 | - } | 351 | + |
372 | 352 | ||
373 | 353 | ||
374 | var container_div = d3.select("#most-used-tags-body"); | 354 | var container_div = d3.select("#most-used-tags-body"); |
@@ -378,8 +358,8 @@ var charts = { | @@ -378,8 +358,8 @@ var charts = { | ||
378 | .style("background","#ddf8e7") | 358 | .style("background","#ddf8e7") |
379 | .append('g') | 359 | .append('g') |
380 | .attr("transform", "translate(0,0)") | 360 | .attr("transform", "translate(0,0)") |
381 | - .style("width", width) | ||
382 | - .attr("height", height); | 361 | + .attr("width", "100%") |
362 | + .attr("height", height - 60); | ||
383 | 363 | ||
384 | 364 | ||
385 | var color = d3.scaleLinear() | 365 | var color = d3.scaleLinear() |
@@ -392,7 +372,8 @@ var charts = { | @@ -392,7 +372,8 @@ var charts = { | ||
392 | return Math.floor(Math.random() * (max - min)) + min; | 372 | return Math.floor(Math.random() * (max - min)) + min; |
393 | } | 373 | } |
394 | 374 | ||
395 | - var xScale = d3.scaleSqrt().domain([min(), max()]).range([10,80]); | 375 | + var xScale = d3.scaleSqrt().domain([d3.min(dataset, function(d){ return d['count']}), |
376 | + d3.max(dataset, function(d){ return d.count; })]).range([100,200]); | ||
396 | var tag_cloud = svg.selectAll('.tag-cloud-div') | 377 | var tag_cloud = svg.selectAll('.tag-cloud-div') |
397 | .data(dataset) | 378 | .data(dataset) |
398 | .enter() | 379 | .enter() |
@@ -420,23 +401,29 @@ var charts = { | @@ -420,23 +401,29 @@ var charts = { | ||
420 | .text(function(d){ | 401 | .text(function(d){ |
421 | return d['name']; | 402 | return d['name']; |
422 | }) | 403 | }) |
404 | + .attr("text-anchor", "middle") | ||
423 | .attr("x", function(d){ | 405 | .attr("x", function(d){ |
424 | - return xScale(d['count'])*0.2; | 406 | + return xScale(d['count'])*1.2/2; |
425 | }) | 407 | }) |
426 | .attr("y", function(d){ | 408 | .attr("y", function(d){ |
427 | - return xScale(d["count"])*0.2; | 409 | + return xScale(d["count"])*0.4/2; |
428 | }) | 410 | }) |
429 | .attr("class", "tag-name") | 411 | .attr("class", "tag-name") |
430 | - .attr("fill", "#ffffff"); | 412 | + .attr("fill", "#ffffff") |
413 | + .style("font-size", function(d){ | ||
414 | + return xScale(d["count"])*0.1 + "px"; | ||
415 | + }); | ||
431 | 416 | ||
432 | 417 | ||
433 | var simulation = d3.forceSimulation() | 418 | var simulation = d3.forceSimulation() |
434 | .force("x", d3.forceX(width/2).strength(0.05)) | 419 | .force("x", d3.forceX(width/2).strength(0.05)) |
435 | .force("y", d3.forceY(height/2).strength(0.05)) | 420 | .force("y", d3.forceY(height/2).strength(0.05)) |
436 | - .force("collide", d3.forceCollide(function(d){ | ||
437 | - return xScale(d['count'])*0.4; | ||
438 | - })); | ||
439 | - | 421 | + .force("charge", d3.forceManyBody().strength(-120).distanceMax(300) |
422 | + .distanceMin(0)); | ||
423 | + /* | ||
424 | + .force("collide", d3.forceCollide(function(d){ | ||
425 | + return xScale(d['count'])*0.3; | ||
426 | + }))*/ | ||
440 | //simulation | 427 | //simulation |
441 | simulation.nodes(dataset) | 428 | simulation.nodes(dataset) |
442 | .on('tick', ticked); //so all data points are attached to it | 429 | .on('tick', ticked); //so all data points are attached to it |
@@ -448,6 +435,65 @@ var charts = { | @@ -448,6 +435,65 @@ var charts = { | ||
448 | } | 435 | } |
449 | 436 | ||
450 | }); | 437 | }); |
438 | + }, | ||
439 | + month_heatmap: function(data, target){ | ||
440 | + | ||
441 | + | ||
442 | + if(target == '#right-chart-body' && $('#month-chart').length != 0){ | ||
443 | + $('#month-chart').fadeOut(); | ||
444 | + $('#month-chart').remove(); | ||
445 | + } | ||
446 | + | ||
447 | + if(target == "#bottom-right-chart-body" && $('#weekly-chart').length != 0){ | ||
448 | + $('#weekly-chart').fadeOut(); | ||
449 | + $('#weekly-chart').remove(); | ||
450 | + } | ||
451 | + | ||
452 | + var svg = d3.select(target).append('svg') | ||
453 | + .attr('width', 300) | ||
454 | + .attr('height', 200); | ||
455 | + | ||
456 | + if (target == "#right-chart-body"){ | ||
457 | + svg.attr('id', 'month-chart'); | ||
458 | + } | ||
459 | + | ||
460 | + if (target == "#bottom-right-chart-body"){ | ||
461 | + svg.attr('id', 'weekly-chart'); | ||
462 | + } | ||
463 | + | ||
464 | + //color range | ||
465 | + var color = d3.scaleLinear().range(["#29c8b8", '#149e91']).domain([0, d3.max(data, function(d){ return d.count; })]); | ||
466 | + | ||
467 | + var rects = svg.selectAll("rect") | ||
468 | + .data(data) | ||
469 | + .enter() | ||
470 | + .append("g"); | ||
471 | + rect_width = 40; | ||
472 | + rect_height = 40; | ||
473 | + rects.append("rect") | ||
474 | + .attr("width", rect_width) | ||
475 | + .attr("height", rect_height) | ||
476 | + .attr("class", "day_rect") | ||
477 | + .attr("x", function(d, i){ | ||
478 | + | ||
479 | + return rect_width* (i % 7); | ||
480 | + }).attr("y", function(d, i){ | ||
481 | + return rect_height*(Math.floor(i / 7)); | ||
482 | + }).attr("fill", function(d, i ){ | ||
483 | + return color(d.count); | ||
484 | + }); | ||
485 | + | ||
486 | + rects.append("text") | ||
487 | + .text( function(d){ | ||
488 | + return d.day; | ||
489 | + }).attr("fill", "white") | ||
490 | + .attr("text-anchor", "middle") | ||
491 | + .attr("x", function(d, i){ | ||
492 | + return rect_width* ( i % 7) + rect_width/2; | ||
493 | + }).attr("y", function(d, i){ | ||
494 | + return rect_height*(Math.floor( i / 7)) + rect_height/2; | ||
495 | + }); | ||
496 | + | ||
451 | } | 497 | } |
452 | } | 498 | } |
453 | 499 |
analytics/templates/analytics/category.html
analytics/templates/analytics/general.html
@@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
7 | {% endblock style %} | 7 | {% endblock style %} |
8 | 8 | ||
9 | {% block javascript %} | 9 | {% block javascript %} |
10 | + | ||
10 | <script type="text/javascript" src="{% static "analytics/js/charts.js" %}"></script> | 11 | <script type="text/javascript" src="{% static "analytics/js/charts.js" %}"></script> |
11 | <script type="text/javascript" src=" {% static "analytics/js/behavior.js" %} "></script> | 12 | <script type="text/javascript" src=" {% static "analytics/js/behavior.js" %} "></script> |
12 | {% endblock javascript %} | 13 | {% endblock javascript %} |
@@ -68,19 +69,20 @@ | @@ -68,19 +69,20 @@ | ||
68 | <section class="bottom-section"> | 69 | <section class="bottom-section"> |
69 | <div class="chart left-chart"> | 70 | <div class="chart left-chart"> |
70 | 71 | ||
71 | - | 72 | + <h4>{% trans "Most accessed " %}</h4> |
72 | <div id="left-data-selector"> | 73 | <div id="left-data-selector"> |
74 | + | ||
73 | 75 | ||
74 | <div class="selector" data-url="categories"> | 76 | <div class="selector" data-url="categories"> |
75 | - <p> {% trans "most accessed categories" %} </p> | 77 | + <p> {% trans "Most accessed categories" %} </p> |
76 | </div> | 78 | </div> |
77 | 79 | ||
78 | <div class="selector" data-url="subjects"> | 80 | <div class="selector" data-url="subjects"> |
79 | - <p> {% trans "most accessed subjects" %} </p> | 81 | + <p> {% trans "Most accessed subjects" %} </p> |
80 | </div> | 82 | </div> |
81 | 83 | ||
82 | <div class="selector" data-url="resources"> | 84 | <div class="selector" data-url="resources"> |
83 | - <p> {% trans "most accessed resource" %} </p> | 85 | + <p> {% trans "Most accessed resource" %} </p> |
84 | </div> | 86 | </div> |
85 | 87 | ||
86 | </div> | 88 | </div> |
@@ -88,13 +90,36 @@ | @@ -88,13 +90,36 @@ | ||
88 | </div> | 90 | </div> |
89 | <div class="chart middle-chart"> | 91 | <div class="chart middle-chart"> |
90 | <article> | 92 | <article> |
91 | - <h4>{% trans "most active users" %}</h4> | 93 | + <h4>{% trans "Most active users" %}</h4> |
92 | </article> | 94 | </article> |
93 | 95 | ||
94 | </div> | 96 | </div> |
95 | <div class="chart right-chart"> | 97 | <div class="chart right-chart"> |
96 | - | 98 | + <div id="month_selector_div"> |
99 | + <h4>{% trans "Amount of access in: " %} | ||
100 | + <select id="month_selector"> | ||
101 | + {% for month in months %} | ||
102 | + <option>{{month}}</option> | ||
103 | + {% endfor %} | ||
104 | + | ||
105 | + </select> | ||
106 | + </h4> | ||
107 | + </div> | ||
97 | 108 | ||
109 | + <div id="right-chart-body"> | ||
110 | + | ||
111 | + </div> | ||
112 | + | ||
113 | + <div class='input-group date'> | ||
114 | + <label>{% trans "Select the begin of the week: " %}</label> | ||
115 | + <input type='text' class="datepicker form-control" /> | ||
116 | + <span class="input-group-addon"> | ||
117 | + <span class="glyphicon glyphicon-calendar"></span> | ||
118 | + </span> | ||
119 | + </div> | ||
120 | + <div id="bottom-right-chart-body"> | ||
121 | + | ||
122 | + </div> | ||
98 | </div> | 123 | </div> |
99 | </section> | 124 | </section> |
100 | 125 |
analytics/urls.py
@@ -4,6 +4,7 @@ from . import views | @@ -4,6 +4,7 @@ from . import views | ||
4 | 4 | ||
5 | urlpatterns = [ | 5 | urlpatterns = [ |
6 | url(r'^view/general/$', views.GeneralView.as_view(), name='view_general'), | 6 | url(r'^view/general/$', views.GeneralView.as_view(), name='view_general'), |
7 | + url(r'^view/category/data$', views.CategoryView.as_view(), name='view_category_data'), | ||
7 | 8 | ||
8 | #"api" callls | 9 | #"api" callls |
9 | url(r'^most_used_tags/$', views.most_used_tags, name="most_used_tags"), | 10 | url(r'^most_used_tags/$', views.most_used_tags, name="most_used_tags"), |
@@ -11,4 +12,6 @@ urlpatterns = [ | @@ -11,4 +12,6 @@ urlpatterns = [ | ||
11 | url(r'^most_accessed_categories/$', views.most_accessed_categories, name = "most_accessed_categories"), | 12 | url(r'^most_accessed_categories/$', views.most_accessed_categories, name = "most_accessed_categories"), |
12 | url(r'^most_accessed_resources/$', views.most_accessed_resource_kind, name= "most_accessed_resources"), | 13 | url(r'^most_accessed_resources/$', views.most_accessed_resource_kind, name= "most_accessed_resources"), |
13 | url(r'^most_active_users/$', views.most_active_users, name= "most_active_users"), | 14 | url(r'^most_active_users/$', views.most_active_users, name= "most_active_users"), |
15 | + url(r'^amount_active_users_per_day/$', views.most_active_users_in_a_month, name="most_active_users_in_a_month"), | ||
16 | + url(r'^get_days_of_the_week_log/$', views.get_days_of_the_week_log, name="get_days_of_the_week_log"), | ||
14 | ] | 17 | ] |
15 | \ No newline at end of file | 18 | \ No newline at end of file |
analytics/views.py
@@ -13,6 +13,10 @@ import operator | @@ -13,6 +13,10 @@ import operator | ||
13 | from django.utils.translation import ugettext_lazy as _ | 13 | from django.utils.translation import ugettext_lazy as _ |
14 | from django.shortcuts import render, get_object_or_404, redirect | 14 | from django.shortcuts import render, get_object_or_404, redirect |
15 | 15 | ||
16 | +from datetime import date, timedelta, datetime | ||
17 | +import calendar | ||
18 | +from collections import OrderedDict | ||
19 | + | ||
16 | 20 | ||
17 | class GeneralView(generic.TemplateView): | 21 | class GeneralView(generic.TemplateView): |
18 | template_name = "analytics/general.html" | 22 | template_name = "analytics/general.html" |
@@ -20,20 +24,31 @@ class GeneralView(generic.TemplateView): | @@ -20,20 +24,31 @@ class GeneralView(generic.TemplateView): | ||
20 | def dispatch(self, request, *args, **kwargs): | 24 | def dispatch(self, request, *args, **kwargs): |
21 | 25 | ||
22 | if not request.user.is_staff: | 26 | if not request.user.is_staff: |
23 | - self.template_name = "analytics/category.html" | 27 | + return redirect('analytics:view_category_data') |
24 | return super(GeneralView, self).dispatch(request, *args, **kwargs) | 28 | return super(GeneralView, self).dispatch(request, *args, **kwargs) |
25 | 29 | ||
26 | 30 | ||
27 | def get_context_data(self, **kwargs): | 31 | def get_context_data(self, **kwargs): |
28 | context = {} | 32 | context = {} |
33 | + | ||
34 | + context['months'] = [_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'), | ||
35 | + _('September'), _('October'), _('November'), _('December')] | ||
29 | 36 | ||
30 | return context | 37 | return context |
31 | 38 | ||
32 | 39 | ||
33 | 40 | ||
34 | def most_used_tags(request): | 41 | def most_used_tags(request): |
35 | - tags = Tag.objects.all() | 42 | + |
43 | + | ||
44 | + data = get_most_used_tags() | ||
45 | + data = sorted(data.values(), key = lambda x: x['count'], reverse=True ) | ||
46 | + data = data[:15] #get top 15 tags | ||
47 | + return JsonResponse(data, safe= False) | ||
48 | + | ||
49 | +def get_most_used_tags(): | ||
36 | 50 | ||
51 | + tags = Tag.objects.all() | ||
37 | data = {} | 52 | data = {} |
38 | #grab all references to that tag | 53 | #grab all references to that tag |
39 | for tag in tags: | 54 | for tag in tags: |
@@ -49,17 +64,31 @@ def most_used_tags(request): | @@ -49,17 +64,31 @@ def most_used_tags(request): | ||
49 | else: | 64 | else: |
50 | data[tag.name] = {'name': tag.name} | 65 | data[tag.name] = {'name': tag.name} |
51 | data[tag.name]['count'] = resources_count | 66 | data[tag.name]['count'] = resources_count |
52 | - | ||
53 | - data = sorted(data.values(), key = lambda x: x['count'], reverse=True ) | ||
54 | - data = data[:30] #get top 30 tags | ||
55 | - return JsonResponse(data, safe= False) | ||
56 | - | ||
57 | - | ||
58 | -def heatmap(request): | ||
59 | - return None | 67 | + return data |
68 | + | ||
69 | + | ||
70 | +def most_active_users_in_a_month(request): | ||
71 | + params = request.GET | ||
72 | + days = get_days_of_the_month(params['month']) | ||
73 | + mappings = {_('January'): 1, _('February'): 2, _('March'): 3, _('April'): 4, _('May'): 5, _('June'): 6, _('July'): 7 | ||
74 | + , _('August'): 8, _('September'): 9, _('October'): 10, _('November'): 11, _('December'): 12} | ||
75 | + | ||
76 | + days_list = [] | ||
77 | + for day in days: | ||
78 | + built_date = date(date.today().year, mappings[params['month']], day) | ||
79 | + days_list.append(built_date) | ||
80 | + data = activity_in_timestamp(days_list) | ||
81 | + data = [{"day": day.day, "count": day_count} for day, day_count in data.items()] | ||
82 | + return JsonResponse(data, safe=False) | ||
60 | 83 | ||
61 | 84 | ||
85 | +def activity_in_timestamp(days): | ||
86 | + data = {} | ||
87 | + for day in days: | ||
88 | + day_count = Log.objects.filter(datetime__date = day).count() | ||
89 | + data[day] = day_count | ||
62 | 90 | ||
91 | + return data | ||
63 | """ | 92 | """ |
64 | Subject view that returns a list of the most used subjects """ | 93 | Subject view that returns a list of the most used subjects """ |
65 | 94 | ||
@@ -68,44 +97,45 @@ def most_accessed_subjects(request): | @@ -68,44 +97,45 @@ def most_accessed_subjects(request): | ||
68 | data = {} #empty response | 97 | data = {} #empty response |
69 | 98 | ||
70 | data = Log.objects.filter(resource = 'subject') | 99 | data = Log.objects.filter(resource = 'subject') |
71 | - subjects = {} | ||
72 | - for datum in data: | ||
73 | - if datum.context: | ||
74 | - subject_id = datum.context['subject_id'] | ||
75 | - if subject_id in subjects.keys(): | ||
76 | - subjects[subject_id]['count'] = subjects[subject_id]['count'] + 1 | ||
77 | - | ||
78 | - else: | ||
79 | - subjects[subject_id] = {'name': datum.context['subject_name'], 'count': 1 } | ||
80 | - | 100 | + subjects = get_log_count_of_resource(resource='subject') |
81 | #order the values of the dictionary by the count in descendent order | 101 | #order the values of the dictionary by the count in descendent order |
82 | subjects = sorted(subjects.values(), key = lambda x: x['count'], reverse=True ) | 102 | subjects = sorted(subjects.values(), key = lambda x: x['count'], reverse=True ) |
83 | subjects = subjects[:5] | 103 | subjects = subjects[:5] |
84 | 104 | ||
85 | return JsonResponse(subjects, safe=False) | 105 | return JsonResponse(subjects, safe=False) |
86 | 106 | ||
107 | +def get_log_count_of_resource(resource = ''): | ||
108 | + | ||
109 | + data = Log.objects.filter(resource = resource) | ||
110 | + items = {} | ||
111 | + for datum in data: | ||
112 | + if datum.context: | ||
113 | + item_id = datum.context[resource + '_id'] | ||
114 | + if item_id in items.keys(): | ||
115 | + items[item_id]['count'] = items[item_id]['count'] + 1 | ||
116 | + else: | ||
117 | + items[item_id] = {'name': datum.context[resource+'_name'], 'count': 1} | ||
118 | + return items | ||
87 | 119 | ||
88 | 120 | ||
89 | def most_accessed_categories(request): | 121 | def most_accessed_categories(request): |
90 | data = {} | 122 | data = {} |
91 | 123 | ||
92 | data = Log.objects.filter(resource = 'category') | 124 | data = Log.objects.filter(resource = 'category') |
93 | - categories = {} | ||
94 | - for datum in data: | ||
95 | - if datum.context: | ||
96 | - category_id = datum.context['category_id'] | ||
97 | - if category_id in categories.keys(): | ||
98 | - categories[category_id]['count'] = categories[category_id]['count'] + 1 | ||
99 | - else: | ||
100 | - categories[category_id] = {'name': datum.context['category_name'], 'count': 1 } | 125 | + categories = get_log_count_of_resource('category') |
126 | + | ||
127 | + | ||
101 | 128 | ||
102 | categories = sorted(categories.values(), key = lambda x: x['count'], reverse = True) | 129 | categories = sorted(categories.values(), key = lambda x: x['count'], reverse = True) |
103 | categories = categories[:5] | 130 | categories = categories[:5] |
104 | return JsonResponse(categories, safe= False) | 131 | return JsonResponse(categories, safe= False) |
105 | 132 | ||
106 | -def most_accessed_resource_kind(request): | ||
107 | - resources = Resource.objects.distinct() | ||
108 | 133 | ||
134 | +def get_resource_subclasses_count(): | ||
135 | + """ | ||
136 | + get the amount of objects in each sub_class of resource | ||
137 | + """ | ||
138 | + resources = Resource.objects.distinct() | ||
109 | data = {} | 139 | data = {} |
110 | for resource in resources: | 140 | for resource in resources: |
111 | key = resource.__dict__['_my_subclass'] | 141 | key = resource.__dict__['_my_subclass'] |
@@ -114,6 +144,13 @@ def most_accessed_resource_kind(request): | @@ -114,6 +144,13 @@ def most_accessed_resource_kind(request): | ||
114 | else: | 144 | else: |
115 | data[key] = {'name': key, 'count': 1} | 145 | data[key] = {'name': key, 'count': 1} |
116 | 146 | ||
147 | + return data | ||
148 | + | ||
149 | + | ||
150 | +def most_accessed_resource_kind(request): | ||
151 | + | ||
152 | + data = get_resource_subclasses_count() | ||
153 | + | ||
117 | data = sorted(data.values(), key = lambda x: x['count'], reverse= True) | 154 | data = sorted(data.values(), key = lambda x: x['count'], reverse= True) |
118 | mapping = {} | 155 | mapping = {} |
119 | mapping['pdffile'] = str(_('PDF File')) | 156 | mapping['pdffile'] = str(_('PDF File')) |
@@ -136,4 +173,46 @@ def most_active_users(request): | @@ -136,4 +173,46 @@ def most_active_users(request): | ||
136 | user_object = User.objects.get(id=user['user_id']) | 173 | user_object = User.objects.get(id=user['user_id']) |
137 | user['image'] = user_object.image_url | 174 | user['image'] = user_object.image_url |
138 | user['user'] = user_object.social_name | 175 | user['user'] = user_object.social_name |
139 | - return JsonResponse(fifty_users, safe=False) | ||
140 | \ No newline at end of file | 176 | \ No newline at end of file |
177 | + return JsonResponse(fifty_users, safe=False) | ||
178 | + | ||
179 | + | ||
180 | + | ||
181 | + | ||
182 | +def get_days_of_the_month(month): | ||
183 | + | ||
184 | + #get current year | ||
185 | + year = date.today().year | ||
186 | + mappings = {_('January'): 1, _('February'): 2, _('March'): 3, _('April'): 4, _('May'): 5, _('June'): 6, _('July'): 7 | ||
187 | + , _('August'): 8, _('September'): 9, _('October'): 10, _('November'): 11, _('December'): 12} | ||
188 | + | ||
189 | + c = calendar.Calendar() | ||
190 | + days = c.itermonthdays(year, mappings[month]) | ||
191 | + days_set = set() | ||
192 | + for day in days: | ||
193 | + days_set.add(day) | ||
194 | + | ||
195 | + days_set.remove(0) #because 0 is not aan actual day from that month | ||
196 | + return days_set | ||
197 | + | ||
198 | + | ||
199 | + | ||
200 | +def get_days_of_the_week_log(request): | ||
201 | + date = request.GET['date'] | ||
202 | + date = datetime.strptime( date, '%m/%d/%Y',) | ||
203 | + days = get_days_of_the_week(date) | ||
204 | + data = activity_in_timestamp(days) | ||
205 | + data = [{"day": day.day, "count": day_count} for day, day_count in data.items()] | ||
206 | + | ||
207 | + return JsonResponse(data, safe= False) | ||
208 | + | ||
209 | +def get_days_of_the_week(date): | ||
210 | + | ||
211 | + days_set = [] | ||
212 | + days_set.append(date) | ||
213 | + for j in range(1, 7): | ||
214 | + days_set.append(date + timedelta(days=j)) | ||
215 | + return days_set | ||
216 | + | ||
217 | + | ||
218 | +class CategoryView(generic.TemplateView): | ||
219 | + template_name = "analytics/category.html" |
subjects/templates/subjects/home.html
@@ -15,16 +15,21 @@ | @@ -15,16 +15,21 @@ | ||
15 | {% endif %} | 15 | {% endif %} |
16 | 16 | ||
17 | 17 | ||
18 | +{% if news %} | ||
19 | + | ||
20 | + | ||
18 | 21 | ||
19 | 22 | ||
20 | <!-- Wrapper for slides --> | 23 | <!-- Wrapper for slides --> |
21 | <div id="myCarousel" class="carousel slide " data-ride="carousel"> | 24 | <div id="myCarousel" class="carousel slide " data-ride="carousel"> |
22 | <!-- Indicators --> | 25 | <!-- Indicators --> |
23 | <ol class="carousel-indicators"> | 26 | <ol class="carousel-indicators"> |
24 | - <li data-target="#myCarousel" data-slide-to="0" class="active"></li> | ||
25 | - <li data-target="#myCarousel" data-slide-to="1"></li> | ||
26 | - <li data-target="#myCarousel" data-slide-to="2"></li> | ||
27 | - <li data-target="#myCarousel" data-slide-to="3"></li> | 27 | + <li data-target="#myCarousel" data-slide-to="0" class="active"></li> |
28 | + {% for new in news %} | ||
29 | + {% if forloop.counter != news.count %} | ||
30 | + <li data-target="#myCarousel" data-slide-to="{{forloop.counter}}"></li> | ||
31 | + {% endif %} | ||
32 | + {% endfor %} | ||
28 | </ol> | 33 | </ol> |
29 | 34 | ||
30 | <div class="carousel-inner" role="listbox"> | 35 | <div class="carousel-inner" role="listbox"> |
@@ -52,6 +57,7 @@ | @@ -52,6 +57,7 @@ | ||
52 | </a> | 57 | </a> |
53 | </div> | 58 | </div> |
54 | 59 | ||
60 | +{% endif %} | ||
55 | 61 | ||
56 | 62 | ||
57 | 63 |
subjects/views.py
@@ -40,6 +40,7 @@ from io import BytesIO | @@ -40,6 +40,7 @@ from io import BytesIO | ||
40 | from itertools import chain | 40 | from itertools import chain |
41 | from django.core import serializers | 41 | from django.core import serializers |
42 | from rest_framework.renderers import JSONRenderer | 42 | from rest_framework.renderers import JSONRenderer |
43 | +from rest_framework.parsers import JSONParser | ||
43 | 44 | ||
44 | from users.serializers import UserSerializer | 45 | from users.serializers import UserSerializer |
45 | from file_link.serializers import SimpleFileLinkSerializer, CompleteFileLinkSerializer | 46 | from file_link.serializers import SimpleFileLinkSerializer, CompleteFileLinkSerializer |
@@ -871,6 +872,21 @@ def realize_restore(request, subject): | @@ -871,6 +872,21 @@ def realize_restore(request, subject): | ||
871 | if zip_file: | 872 | if zip_file: |
872 | if zipfile.is_zipfile(zip_file): | 873 | if zipfile.is_zipfile(zip_file): |
873 | file = zipfile.ZipFile(zip_file) | 874 | file = zipfile.ZipFile(zip_file) |
874 | - print(file.namelist()) | 875 | + total_files = len(file.namelist()) |
876 | + | ||
877 | + json_file = file.namelist()[total_files-1] | ||
878 | + | ||
879 | + dst_path = os.path.join(settings.MEDIA_ROOT, "tmp") | ||
880 | + | ||
881 | + path = file.extract(json_file, dst_path) | ||
882 | + | ||
883 | + for line in open(path, 'r'): | ||
884 | + print(line) | ||
885 | + #print(json.loads(line)) | ||
886 | + | ||
887 | + # with open(path) as bkp_file: | ||
888 | + # data = json.loads(bkp_file.read()) | ||
889 | + | ||
890 | + # print(data) | ||
875 | 891 | ||
876 | return JsonResponse({'message': 'ok'}) | 892 | return JsonResponse({'message': 'ok'}) |
877 | \ No newline at end of file | 893 | \ No newline at end of file |