Commit 7714c440f6e41b8f87515e8acf041b91f003698e

Authored by Felipe Bormann
1 parent 2102fa3d

started building general report, tag data is ready but tag cloud chart is not, a…

…dded gradient where it was needed
analytics/__init__.py 0 → 100644
analytics/admin.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.contrib import admin
  2 +
  3 +# Register your models here.
analytics/apps.py 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +from django.apps import AppConfig
  2 +
  3 +
  4 +class AnalyticsConfig(AppConfig):
  5 + name = 'analytics'
analytics/migrations/__init__.py 0 → 100644
analytics/models.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.db import models
  2 +
  3 +# Create your models here.
analytics/static/.sass-cache/9bdb779ec82a4a96f72be09b83b7c997addd0129/general.sassc 0 → 100644
No preview for this file type
analytics/static/analytics/general.css 0 → 100644
@@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
  1 +.report-body {
  2 + border: 1px solid #3ebeb4;
  3 + border-radius: 20px;
  4 + padding: 10px; }
  5 +
  6 +#general-report-header {
  7 + height: 10%;
  8 + display: block; }
  9 + #general-report-header h3 {
  10 + color: #009688; }
  11 + #general-report-header ul {
  12 + float: right;
  13 + display: inline-flex;
  14 + width: 50%;
  15 + height: 15%; }
  16 + #general-report-header ul li {
  17 + margin-right: 2%;
  18 + width: 50%;
  19 + color: white; }
  20 + #general-report-header ul li div.selected {
  21 + background-color: #4dcfbd;
  22 + width: 100%;
  23 + text-align: center;
  24 + border-radius: 20px; }
  25 + #general-report-header ul li div {
  26 + background-color: #0f8a9a;
  27 + width: 100%;
  28 + text-align: center;
  29 + border-radius: 20px; }
  30 +
  31 +#most-used-tags-header {
  32 + background: linear-gradient(to right, #0e8999, #6bf0ce);
  33 + height: 40px;
  34 + border-radius: 10px;
  35 + color: #ffffff; }
  36 +
  37 +div.tag-cloud {
  38 + width: 10%;
  39 + border-radius: 25px;
  40 + color: #ffffff;
  41 + background-color: #52b7bd; }
  42 +
  43 +/*# sourceMappingURL=general.css.map */
analytics/static/analytics/general.css.map 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +{
  2 +"version": 3,
  3 +"mappings": "AAAA,YAAY;EACX,MAAM,EAAE,iBAAiB;EACzB,aAAa,EAAE,IAAI;EACnB,OAAO,EAAE,IAAI;;AAGd,sBAAsB;EACrB,MAAM,EAAE,GAAG;EACX,OAAO,EAAE,KAAK;EACd,yBAAE;IACD,KAAK,EAAE,OAAO;EAEf,yBAAE;IACD,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,WAAW;IACpB,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,GAAG;IAEX,4BAAE;MACD,YAAY,EAAE,EAAE;MAChB,KAAK,EAAE,GAAG;MACV,KAAK,EAAE,KAAK;MAEZ,yCAAY;QACX,gBAAgB,EAAE,OAAO;QACzB,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,MAAM;QAClB,aAAa,EAAE,IAAI;MAEpB,gCAAG;QACF,gBAAgB,EAAE,OAAO;QACzB,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,MAAM;QAClB,aAAa,EAAE,IAAI;;AAIvB,sBAAsB;EACrB,UAAU,EAAE,2CAA2C;EACvD,MAAM,EAAE,IAAI;EACZ,aAAa,EAAE,IAAI;EACnB,KAAK,EAAE,OAAO;;AAEf,aAAa;EACZ,KAAK,EAAE,GAAG;EACV,aAAa,EAAE,IAAI;EACnB,KAAK,EAAE,OAAO;EACd,gBAAgB,EAAE,OAAO",
  4 +"sources": ["general.sass"],
  5 +"names": [],
  6 +"file": "general.css"
  7 +}
0 \ No newline at end of file 8 \ No newline at end of file
analytics/static/analytics/general.sass 0 → 100644
@@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
  1 +.report-body
  2 + border: 1px solid #3ebeb4
  3 + border-radius: 20px
  4 + padding: 10px
  5 +
  6 +
  7 +#general-report-header
  8 + height: 10%
  9 + display: block
  10 + h3
  11 + color: #009688
  12 +
  13 + ul
  14 + float: right
  15 + display: inline-flex
  16 + width: 50%
  17 + height: 15%
  18 +
  19 + li
  20 + margin-right: 2%
  21 + width: 50%
  22 + color: white
  23 +
  24 + div.selected
  25 + background-color: #4dcfbd
  26 + width: 100%
  27 + text-align: center
  28 + border-radius: 20px
  29 +
  30 + div
  31 + background-color: #0f8a9a
  32 + width: 100%
  33 + text-align: center
  34 + border-radius: 20px
  35 +
  36 +
  37 +
  38 +#most-used-tags-header
  39 + background: linear-gradient(to right, #0e8999, #6bf0ce)
  40 + height: 40px
  41 + border-radius: 10px
  42 + color: #ffffff
  43 +
  44 +div.tag-cloud
  45 + width: 10%
  46 + border-radius: 25px
  47 + color: #ffffff
  48 + background-color: #52b7bd
0 \ No newline at end of file 49 \ No newline at end of file
analytics/static/analytics/js/charts.js 0 → 100644
@@ -0,0 +1,378 @@ @@ -0,0 +1,378 @@
  1 +/*
  2 + HOME CHARTS
  3 +*/
  4 +
  5 +//Adding this code by @jshanley to create a filter to look for the last child
  6 +
  7 +d3.selection.prototype.first = function() {
  8 + return d3.select(this[0]);
  9 +};
  10 +d3.selection.prototype.last = function() {
  11 + var last = this.size() - 1;
  12 + return d3.select(this[last]);
  13 +};
  14 +
  15 +var charts = {
  16 + build_resource: function(url){
  17 + $.get(url, function(dataset){
  18 +
  19 +
  20 + var width = 600;
  21 + var height = 300;
  22 + var padding = 30;
  23 + var radius = Math.min(width, height) / 2 - padding;
  24 +
  25 + var color = d3.scaleOrdinal(d3.schemeCategory20);
  26 + var new_div = d3.select(".carousel-inner").append("div").attr("class","item");
  27 + var svg = new_div.append("svg").attr("width", width).attr("height", height)
  28 + .style("margin","auto")
  29 + .style("display","block")
  30 + .append('g')
  31 + .attr('transform', 'translate(' + (width / 2) +
  32 + ',' + (height / 2 + padding ) + ')');
  33 +
  34 +
  35 +
  36 + var donutInner = 20;
  37 + var arc = d3.arc()
  38 + .innerRadius(radius - donutInner)
  39 + .outerRadius(radius);
  40 +
  41 + svg.append("text")
  42 + .attr("text-anchor", "middle")
  43 + .attr("x",0 )
  44 + .attr("y", -height/2 )
  45 + .style("font-size", "30px")
  46 + .text("Recursos mais utilizados")
  47 + .attr("fill", "#003333")
  48 + .style("font-weight", "bold")
  49 + .style("font-style", "italic");
  50 +
  51 +
  52 + var pie = d3.pie()
  53 + .value(function(d) { return d[1]; })
  54 + .sort(null);
  55 +
  56 +
  57 +
  58 + var path = svg.selectAll('path')
  59 + .data(pie(dataset))
  60 + .enter()
  61 + .append('path')
  62 + .attr('d', arc)
  63 + .attr('fill', function(d, i) {
  64 + return color(i);
  65 + });
  66 + var labelArc = d3.arc()
  67 + .outerRadius(radius - donutInner + 30)
  68 + .innerRadius(radius + 20 );
  69 +
  70 + //Adding tooltips to each part of the pie chart.
  71 + svg.selectAll("text.pie-tooltip")
  72 + .data(pie(dataset))
  73 + .enter()
  74 + .append("text")
  75 + .attr("id", function(d){
  76 + return d.data[0];
  77 + })
  78 + .attr("class","pie-tooltip")
  79 + .attr('fill',"#172121")
  80 + .attr("transform", function(d) {
  81 + c = labelArc.centroid(d);
  82 + return "translate(" + (c[0]*1.0 - 20) +"," + c[1]*0.8 + ")";
  83 + })
  84 + .attr("dy", ".25em")
  85 + .text(function(d) { return d.data[0] +'('+ d.data[1] +')'; });
  86 +
  87 +
  88 +
  89 + }) // end of the get method
  90 + },
  91 +
  92 + build_bubble_user: function(url){
  93 + $.get(url, function(dataset){
  94 + var width = 600;
  95 + var height = 300;
  96 +
  97 +
  98 + function min(){
  99 + min = 100000000000;
  100 + for(var i = 0; i < dataset.length; i++){
  101 + if (dataset[i]['count'] < min){
  102 + min = dataset[i]['count'];
  103 + }
  104 + }
  105 +
  106 + return min
  107 + }
  108 +
  109 + function max(){
  110 + max = 0;
  111 + for(var i = 0; i < dataset.length; i++){
  112 + if (dataset[i]['count'] > max){
  113 + max = dataset[i]['count'];
  114 + }
  115 + }
  116 +
  117 + return max
  118 + }
  119 +
  120 +
  121 +
  122 + var color = d3.scaleOrdinal(d3.schemeCategory20);
  123 + //adding new div to carousel-inner div
  124 + var new_div = d3.select(".carousel-inner").append("div").attr("class","item");
  125 + var radiusScale = d3.scaleSqrt().domain([min(), max()]).range([10,50]);
  126 + var svg = new_div.append("svg").attr("width", width).attr("height", height)
  127 + .style("margin","auto")
  128 + .style("display","block")
  129 + .append('g')
  130 + .attr("transform", "translate(0,0)")
  131 + .attr("width", width)
  132 + .attr("height", height);
  133 +
  134 + //adding svg title
  135 +
  136 + svg.append("text")
  137 + .attr("text-anchor", "middle")
  138 + .attr("x", width/2 )
  139 + .attr("y", 30)
  140 + .style("font-size", "30px")
  141 + .text("Usuários mais ativos no Amadeus")
  142 + .attr("fill", "#003333")
  143 + .style("font-weight", "bold")
  144 + .style("font-style", "italic");
  145 +
  146 + var simulation = d3.forceSimulation()
  147 + .force("x", d3.forceX(width/2).strength(0.05))
  148 + .force("y", d3.forceY(height/2).strength(0.05))
  149 + .force("collide", d3.forceCollide(function(d){
  150 + return radiusScale(d['count']);
  151 + }));
  152 +
  153 + //First I create as many groups as datapoints so
  154 + //it can hold all other objects (circle, texts, images)
  155 + var groups = svg.selectAll('.users-item')
  156 + .data(dataset)
  157 + .enter()
  158 + .append("g")
  159 + .attr("class",".user-dot");
  160 +
  161 + //Create circles to be drawn
  162 + var circles = groups
  163 + .append('circle')
  164 + .attr("r", function(d){
  165 + return radiusScale(d['count']);
  166 + })
  167 +
  168 + .attr("fill", function(d){
  169 + return 'url('+'#'+'user_'+d['user_id']+')';
  170 + });
  171 +
  172 +
  173 +
  174 + //Add texts to show user names
  175 + groups.append("text")
  176 + .text(function(d){
  177 + return d['user'] +'('+ d['count'] + ')';
  178 + }).attr("fill", "#FFFFFF")
  179 + .attr("id", function(d){
  180 + return "user_tooltip_"+d['user_id'];
  181 + }).style("display", "none");
  182 +
  183 +
  184 + groups.on("mouseover", function(d){
  185 + $("#"+"user_tooltip_"+d['user_id']).show();
  186 + });
  187 +
  188 +
  189 + groups.on("mouseout", function(d){
  190 + $("#"+"user_tooltip_"+d['user_id']).hide();
  191 + });
  192 +
  193 + var defs = groups.append('svg:defs');
  194 +
  195 + //Attching images to bubbles
  196 + defs.append("svg:pattern")
  197 + .attr("id", function(d){
  198 + return "user_"+d['user_id'];
  199 + })
  200 + .attr("width", function(d){
  201 + return radiusScale(d['count']);
  202 + })
  203 + .attr("height", function(d){
  204 + return radiusScale(d['count']);
  205 + })
  206 + .append("svg:image")
  207 + .attr("xlink:href", function(d){
  208 + return d['image'];
  209 + })
  210 + .attr("width",function(d){
  211 + return radiusScale(d['count'])*2;
  212 + })
  213 + .attr("height", function(d){
  214 + return radiusScale(d['count'])*2;
  215 + })
  216 + .attr("x", 0)
  217 + .attr("y", 0);
  218 +
  219 +
  220 +
  221 + //simulation
  222 + simulation.nodes(dataset)
  223 + .on('tick', ticked); //so all data points are attached to it
  224 +
  225 + function ticked(){
  226 + groups.attr("transform", function(d){
  227 + return "translate(" + d.x + "," + d.y + ")";
  228 + })
  229 + }
  230 + });
  231 +
  232 +
  233 + },
  234 +
  235 + most_accessed_subjects: function(url){
  236 + $.get(url, function(dataset){
  237 + var width = 800;
  238 + var height = 300;
  239 +
  240 + var new_div = d3.select(".carousel-inner").append("div").attr("class","item");
  241 +
  242 + var svg = new_div.append("svg").attr("width", "100%").attr("height", height)
  243 + .style("margin","auto")
  244 + .style("display","block");
  245 +
  246 + var barPadding = 2
  247 + var bottomPadding = 15;
  248 + var marginLeft = 170; //Margin Left for all bars inside the graph
  249 +
  250 + var yScale = d3.scaleLinear()
  251 + .domain([0, d3.max(dataset, function(d) { return d.count; })])
  252 + .range([bottomPadding, 260]);
  253 +
  254 + var rects = svg.selectAll("rect")
  255 + .data(dataset)
  256 + .enter()
  257 + .append("g");
  258 +
  259 + rects.append("rect")
  260 + .attr("x", function(d, i){
  261 + return i * (width / dataset.length ) + barPadding + marginLeft ;
  262 + })
  263 + .attr("y", function(d){
  264 + return height - yScale(d.count) - bottomPadding;
  265 + })
  266 + .attr("width",
  267 + width / dataset.length - barPadding
  268 + )
  269 + .attr("height", function(d){
  270 + return yScale(d.count);
  271 + });
  272 +
  273 +
  274 + var tooltipDiv = new_div.append("div").attr("class","bar-tip");
  275 +
  276 + rects.on("mouseover", function(d, i){
  277 + $(this).attr("fill", "red");
  278 + $("#accessed_subject_"+i).show(); //So the tooltip is hidden
  279 + tooltipDiv.transition()
  280 + .duration(200)
  281 + .style("opacity", .9);
  282 + tooltipDiv.html("<p style='font-size:9px'>" + d.name + "( " + d.count + " )" +"</p>")
  283 + .style("left", (i * (width / dataset.length ) + barPadding + marginLeft) + "px")
  284 + .style("top", (height - yScale(d.count) - bottomPadding) + "px");
  285 + });
  286 +
  287 + rects.on("mouseout", function(d, i ){
  288 + $(this).attr("fill", "black");
  289 +
  290 + $("#accessed_subject_"+i).hide(); //So the tooltip shows up
  291 +
  292 +
  293 + tooltipDiv.transition()
  294 + .duration(500)
  295 + .style("opacity", 0);
  296 +
  297 + });
  298 +
  299 +
  300 +
  301 + //Styling title
  302 + svg.append("text")
  303 + .attr("x", width/2)
  304 + .attr("y", 30)
  305 + .attr("text-anchor", "middle")
  306 + .style("font-size", "30px")
  307 + .text("Subjects mais acessados")
  308 + .attr("fill", "#003333")
  309 + .style("font-weight", "bold")
  310 + .style("font-style", "italic");
  311 +
  312 + });
  313 + },
  314 + most_used_tags: function(url){
  315 + $.get(url, function(dataset){
  316 + //get most used tags across all amadeus
  317 + var width = 800;
  318 + var height = 300;
  319 +
  320 + function min(){
  321 + min = 100000000000;
  322 + for(var i = 0; i < dataset.length; i++){
  323 + if (dataset[i]['count'] < min){
  324 + min = dataset[i]['count'];
  325 + }
  326 + }
  327 +
  328 + return min
  329 + }
  330 +
  331 + function max(){
  332 + max = 0;
  333 + for(var i = 0; i < dataset.length; i++){
  334 + if (dataset[i]['count'] > max){
  335 + max = dataset[i]['count'];
  336 + }
  337 + }
  338 +
  339 + return max
  340 + }
  341 +
  342 + console.log(dataset);
  343 +
  344 + var container_div = d3.select("#most-used-tags-body");
  345 + var svg = container_div.append("svg").attr("width", "100%").attr("height", height)
  346 + .style("margin","auto")
  347 + .style("display","block")
  348 + .style("background","#ddf8e7")
  349 + .append('g')
  350 + .attr("transform", "translate(0,0)")
  351 + .attr("width", width)
  352 + .attr("height", height);
  353 +
  354 +
  355 +
  356 + var radiusScale = d3.scaleSqrt().domain([min(), max()]).range([10,50]);
  357 + var tag_cloud = svg.selectAll('.tag-cloud-div')
  358 + .data(dataset)
  359 + .enter()
  360 + .append('g')
  361 + .attr("class", "data-container");
  362 +
  363 +
  364 + var tag_divs = tag_cloud
  365 + .append('div')
  366 + .attr('class', 'tag-cloud')
  367 + .attr('text', function(d){
  368 + return d['name'];
  369 + });
  370 +
  371 + });
  372 + }
  373 +}
  374 +
  375 +charts.most_used_tags('/analytics/most_used_tags');
  376 +//charts.build_resource('/topics/count_resources/');
  377 +//charts.build_bubble_user('/users/get_users_log/');
  378 +//charts.most_accessed_subjects('/subjects/most_accessed_subjects');
0 \ No newline at end of file 379 \ No newline at end of file
analytics/templates/analytics/general.html 0 → 100644
@@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
  1 +{% extends 'base.html' %}
  2 +
  3 +{% load static i18n pagination %}
  4 +{% load django_bootstrap_breadcrumbs %}
  5 +{% block style %}
  6 + <link rel="stylesheet" type="text/css" href="{% static 'analytics/general.css' %}">
  7 +{% endblock style %}
  8 +
  9 +{% block javascript %}
  10 + <script type="text/javascript" src="{% static "analytics/js/charts.js" %}"></script>
  11 +{% endblock javascript %}
  12 +
  13 +{% block breadcrumbs %}
  14 + {{ block.super }}
  15 +
  16 + {% trans 'Analytics General' as general %}
  17 +
  18 + {% breadcrumb general 'dashboard:view_general' %}
  19 +{% endblock %}
  20 +
  21 +
  22 +{% block content %}
  23 + <div id="core-subjects-options-div">
  24 + <ul class="core-subjects-options report-menu-choice">
  25 + <li class="active">
  26 + {% trans "Platform Report" %}
  27 + </li>
  28 + <li>
  29 + {% trans "Category Report" %}
  30 + </li>
  31 + <li>
  32 + {% trans "Subject Report" %}
  33 + </li>
  34 + </ul>
  35 + </div>
  36 +
  37 + <div id="general-report">
  38 + <div id="general-report-header">
  39 + <h3>{% trans "Amadeus Report" %}</h3>
  40 +
  41 + <ul id="report-header-options">
  42 + <li >
  43 + <div class="selected">{% trans "Focus" %}<div>
  44 + </li>
  45 + <li>
  46 + <div>{% trans "Log" %}<div>
  47 + </li>
  48 + </ul>
  49 + </div>
  50 +
  51 + <div class="report-body">
  52 +
  53 + <div id="most-used-tags">
  54 + <div id="most-used-tags-header">
  55 + <h4 >
  56 + {% trans "most used tags" %}
  57 + </h4>
  58 + </div>
  59 + <div id="most-used-tags-body">
  60 +
  61 + </div>
  62 + </div>
  63 + <div class="bottom-section">
  64 + <div class="left-chart"></div>
  65 + <div class="middle-chart"></div>
  66 + <div class="right-chart"></div>
  67 + </div>
  68 +
  69 + </div>
  70 + </div>
  71 +
  72 + <script type="text/javascript">
  73 + </script>
  74 +
  75 +
  76 +{% endblock content %}
0 \ No newline at end of file 77 \ No newline at end of file
analytics/tests.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.test import TestCase
  2 +
  3 +# Create your tests here.
analytics/tests/__init__.py 0 → 100644
analytics/tests/test_api.py 0 → 100644
@@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
  1 +from django.test import TestCase, Client, override_settings
  2 +from django.core.urlresolvers import resolve
  3 +from reports.views import ReportView
  4 +from subjects.models import Subject, Tag
  5 +from users.models import User
  6 +from topics.models import Topic, Resource
  7 +from chat.models import Conversation, TalkMessages
  8 +from datetime import datetime
  9 +from log.models import Log
  10 +from django.db.models import Q
  11 +from ..views import most_used_tags
  12 +from django.http import HttpResponse, JsonResponse
  13 +
  14 +class APIDashBoardTest(TestCase):
  15 +
  16 + def setUp(self):
  17 + self.c = Client()
  18 + self.student = User.objects.create(username = "student01", email= "student01@amadeus.br", password="amadeus")
  19 + if self.c.login(email="student01@amadeus.br", password="amadeus"):
  20 + print("student01 logged in")
  21 +
  22 +
  23 + def test_most_used_tags(self):
  24 + t = Tag(name="felipe")
  25 + t.save()
  26 + t1 = Tag(name="b2")
  27 + t1.save()
  28 +
  29 + s1 = Subject.objects.create(name="subject", visible= True, init_date= datetime.now(), end_date= datetime.now(),
  30 + subscribe_begin = datetime.now(), subscribe_end= datetime.now() )
  31 + s1.tags.add(t)
  32 + s1.save()
  33 + s2 = Subject.objects.create(name="subject dois", visible= True, init_date= datetime.now(), end_date= datetime.now(),
  34 + subscribe_begin = datetime.now(), subscribe_end= datetime.now() )
  35 + s2.tags.add(t)
  36 + s2.save()
  37 + r1 = Resource.objects.create(name="resource um")
  38 + r1.tags.add(t1)
  39 + r1.save()
  40 +
  41 +
  42 + expected_data = {'felipe': 2, 'b2': 1}
  43 + data = self.c.get('/analytics/most_used_tags/')
  44 + print(data)
  45 + self.assertEqual(data, expected_data)
analytics/urls.py 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +from django.conf.urls import url, include
  2 +from . import views
  3 +
  4 +
  5 +urlpatterns = [
  6 + url(r'^view/general/$', views.GeneralView.as_view(), name='view_general'),
  7 +
  8 + #"api" callls
  9 + url(r'^most_used_tags/$', views.most_used_tags, name="most_used_tags"),
  10 +]
0 \ No newline at end of file 11 \ No newline at end of file
analytics/views.py 0 → 100644
@@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
  1 +from django.shortcuts import render
  2 +
  3 +# Create your views here.
  4 +from django.views import generic
  5 +from django.db.models import Count
  6 +
  7 +from subjects.models import Tag, Subject
  8 +from topics.models import Resource
  9 +from users.models import User
  10 +from django.http import HttpResponse, JsonResponse
  11 +
  12 +
  13 +class GeneralView(generic.TemplateView):
  14 + template_name = "analytics/general.html"
  15 +
  16 + def get_context_data(self, **kwargs):
  17 + context = {}
  18 +
  19 + return context
  20 +
  21 +
  22 +
  23 +def most_used_tags(request):
  24 + tags = Tag.objects.all()
  25 +
  26 + data = {}
  27 + #grab all references to that tag
  28 + for tag in tags:
  29 + subjects_count = Subject.objects.filter(tags = tag).count()
  30 + if subjects_count > 0:
  31 + data[tag.name] = {'name': tag.name}
  32 + data[tag.name]['count'] = subjects_count
  33 +
  34 + resources_count = Resource.objects.filter(tags = tag).count()
  35 + if resources_count > 0:
  36 + if data.get(tag.name):
  37 + data[tag.name]['count'] = data[tag.name]['count'] + resources_count
  38 + else:
  39 + data[tag.name] = {'name': tag.name}
  40 + data[tag.name]['count'] = resources_count
  41 +
  42 + data = sorted(data.values(), key = lambda x: x['count'], reverse=True )
  43 + data = data[:30] #get top 30 tags
  44 + return JsonResponse(data, safe= False)
  45 +
  46 +
  47 +def heatmap(request):
  48 + return None
  49 +
  50 +
  51 +
  52 +"""
  53 +Subject view that returns a list of the most used subjects """
  54 +
  55 +
  56 +def most_acessed_subjects(request):
  57 + data = {} #empty response
  58 +
  59 + data = Log.objects.filter(resource = 'subject')
  60 + subjects = {}
  61 + for datum in data:
  62 + if datum.context:
  63 + subject_id = datum.context['subject_id']
  64 + if subject_id in subjects.keys():
  65 + subjects[subject_id]['count'] = subjects[subject_id]['count'] + 1
  66 + else:
  67 + subjects[subject_id] = {'name': datum.context['subject_name'], 'count':0 }
  68 +
  69 +
  70 + #order the values of the dictionary by the count in descendent order
  71 + subjects = sorted(subjects.values(), key = lambda x: x['count'], reverse=True )
  72 + subjects = subjects[:30]
  73 +
  74 + return JsonResponse(subjects, safe=False)
  75 +
  76 +
  77 +
  78 +def most_accessed_categories(request):
  79 + return None
  80 +
  81 +def most_accessed_resource_kind(request):
  82 + return None
  83 +
  84 +
  85 +def get_users_log(request):
  86 + fifty_users = Log.objects.values('user_id').annotate(count = Count('user_id')).order_by('-count')[:50]
  87 + fifty_users = list(fifty_users)
  88 + for user in fifty_users:
  89 + user_object = User.objects.get(id=user['user_id'])
  90 + user['image'] = user_object.image_url
  91 + user['user'] = user_object.social_name
  92 + return JsonResponse(fifty_users, safe=False)
0 \ No newline at end of file 93 \ No newline at end of file