-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #170 from HackAssistant/stats
Add apps stats
- Loading branch information
Showing
12 changed files
with
323 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class StatsConfig(AppConfig): | ||
name = 'stats' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
{% extends 'c3_base.html' %} | ||
|
||
{% block head_title %}Application stats{% endblock %} | ||
{% block panel %} | ||
<h1>Application stats</h1> | ||
<small class="pull-right"><b>Last updated:</b> <span id="update_date"></span></small> | ||
<div class="row"> | ||
<div class="col-md-12"> | ||
<div id="timeseries"> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<div class="col-md-6"> | ||
<h3>Status</h3> | ||
<div id="applications_stats"></div> | ||
</div> | ||
<div class="col-md-6"> | ||
<h3>Gender</h3> | ||
<div id="gender_stats"></div> | ||
</div> | ||
</div> | ||
<h2>T-Shirts sizes</h2> | ||
|
||
<div class="row"> | ||
<div class="col-md-6"> | ||
<h3>All</h3> | ||
<div id="shirts_stats"></div> | ||
</div> | ||
<div class="col-md-6"> | ||
<h3>Confirmed only</h3> | ||
<div id="shirts_stats_confirmed"></div> | ||
</div> | ||
</div> | ||
<h2>Dietary restrictions</h2> | ||
|
||
<div class="row"> | ||
<div class="col-md-6"> | ||
<h3>All</h3> | ||
<div id="diet_stats"></div> | ||
</div> | ||
<div class="col-md-6"> | ||
<h3>Confirmed only</h3> | ||
<div id="diet_stats_confirmed"></div> | ||
</div> | ||
<div class="col-md-12"> | ||
<p><b>Other diet requirements</b> <span id="other_diet"></span></p> | ||
</div> | ||
|
||
</div> | ||
|
||
|
||
{% endblock %} | ||
{% block c3script %} | ||
<script> | ||
$.getJSON('{% url 'api_app_stats' %}', function (data) { | ||
c3.generate({ | ||
bindto: '#timeseries', | ||
data: { | ||
json: data['timeseries'], | ||
keys: { | ||
x: 'date', | ||
value: ['applications'] | ||
} | ||
}, | ||
|
||
axis: { | ||
x: { | ||
type: 'timeseries', | ||
tick: { | ||
format: '%Y-%m-%d' | ||
} | ||
} | ||
} | ||
}); | ||
c3.generate({ | ||
bindto: '#shirts_stats_confirmed', | ||
data: { | ||
json: data['shirt_count_confirmed'], | ||
keys: { | ||
x: 'tshirt_size', | ||
value: ['applications'] | ||
}, | ||
type: 'bar' | ||
|
||
}, | ||
|
||
axis: { | ||
x: { | ||
type: 'category' | ||
} | ||
} | ||
}); | ||
|
||
var status_data = {}; | ||
var sites = []; | ||
$(data['status']).each(function (c, e) { | ||
sites.push(e.status_name); | ||
status_data[e.status_name] = e.applications; | ||
}); | ||
c3.generate({ | ||
bindto: '#applications_stats', | ||
data: { | ||
json: status_data, | ||
type: 'donut' | ||
|
||
}, | ||
donut: { | ||
label: { | ||
format: function (value, ratio, id) { | ||
return value; | ||
} | ||
} | ||
} | ||
}); | ||
var gender_data = {}; | ||
var genders = []; | ||
$(data['gender']).each(function (c, e) { | ||
genders.push(e.gender_name); | ||
gender_data[e.gender_name] = e.applications; | ||
}); | ||
c3.generate({ | ||
bindto: '#gender_stats', | ||
data: { | ||
json: gender_data, | ||
type: 'donut' | ||
|
||
}, | ||
donut: { | ||
label: { | ||
format: function (value, ratio, id) { | ||
return value; | ||
} | ||
} | ||
} | ||
}); | ||
c3.generate({ | ||
bindto: '#shirts_stats', | ||
data: { | ||
json: data['shirt_count'], | ||
keys: { | ||
x: 'tshirt_size', | ||
value: ['applications'] | ||
}, | ||
type: 'bar' | ||
|
||
}, | ||
|
||
axis: { | ||
x: { | ||
type: 'category' | ||
} | ||
} | ||
}); | ||
c3.generate({ | ||
bindto: '#diet_stats', | ||
data: { | ||
json: data['diet'], | ||
keys: { | ||
x: 'diet', | ||
value: ['applications'] | ||
}, | ||
type: 'bar' | ||
|
||
}, | ||
|
||
axis: { | ||
x: { | ||
type: 'category' | ||
} | ||
} | ||
}); | ||
c3.generate({ | ||
bindto: '#diet_stats_confirmed', | ||
data: { | ||
json: data['diet_confirmed'], | ||
keys: { | ||
x: 'diet', | ||
value: ['applications'] | ||
}, | ||
type: 'bar' | ||
|
||
}, | ||
|
||
axis: { | ||
x: { | ||
type: 'category' | ||
} | ||
} | ||
}); | ||
$('#other_diet').html(data['other_diet']); | ||
$('#update_date').html(data['update_time']); | ||
}) | ||
; | ||
|
||
</script> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{% extends 'base_tabs.html' %} | ||
{% load static %} | ||
|
||
|
||
{% block extra_head %} | ||
<link rel="stylesheet" href="{% static 'lib/c3.min.css' %}"> | ||
{% endblock %} | ||
|
||
{% block extra_scripts %} | ||
<script src="https://d3js.org/d3.v3.min.js"></script> | ||
<script src="{% static 'lib/c3.min.js' %}" charset="utf-8"></script> | ||
{% block c3script %}{% endblock %} | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from django.conf.urls import url | ||
from django.views.decorators.cache import cache_page | ||
|
||
from stats import views | ||
|
||
urlpatterns = [ | ||
url(r'^api/apps/$', cache_page(60)(views.app_stats_api), name='api_app_stats'), | ||
url(r'^$', views.AppStats.as_view(), name='app_stats'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from django.db.models import Count | ||
from django.db.models.functions import TruncDate | ||
from django.http import JsonResponse | ||
from django.utils import timezone | ||
|
||
from app.views import TabsView | ||
from applications.models import Application, STATUS, APP_CONFIRMED, GENDERS | ||
from user.mixins import is_organizer, IsOrganizerMixin | ||
|
||
STATUS_DICT = dict(STATUS) | ||
GENDER_DICT = dict(GENDERS) | ||
|
||
|
||
@is_organizer | ||
def app_stats_api(request): | ||
# Status analysis | ||
status_count = Application.objects.all().values('status') \ | ||
.annotate(applications=Count('status')) | ||
status_count = map(lambda x: dict(status_name=STATUS_DICT[x['status']], **x), status_count) | ||
|
||
gender_count = Application.objects.all().values('gender') \ | ||
.annotate(applications=Count('gender')) | ||
gender_count = map(lambda x: dict(gender_name=GENDER_DICT[x['gender']], **x), gender_count) | ||
|
||
shirt_count = Application.objects.values('tshirt_size') \ | ||
.annotate(applications=Count('tshirt_size')) | ||
shirt_count_confirmed = Application.objects.filter(status=APP_CONFIRMED).values('tshirt_size') \ | ||
.annotate(applications=Count('tshirt_size')) | ||
|
||
diet_count = Application.objects.values('diet') \ | ||
.annotate(applications=Count('diet')) | ||
diet_count_confirmed = Application.objects.filter(status=APP_CONFIRMED).values('diet') \ | ||
.annotate(applications=Count('diet')) | ||
other_diets = Application.objects.values('other_diet') | ||
|
||
timeseries = Application.objects.all().annotate(date=TruncDate('submission_date')).values('date').annotate( | ||
applications=Count('date')) | ||
return JsonResponse( | ||
{ | ||
'update_time': timezone.now(), | ||
'status': list(status_count), | ||
'shirt_count': list(shirt_count), | ||
'shirt_count_confirmed': list(shirt_count_confirmed), | ||
'timeseries': list(timeseries), | ||
'gender': list(gender_count), | ||
'diet': list(diet_count), | ||
'diet_confirmed': list(diet_count_confirmed), | ||
'other_diet': ';'.join([el['other_diet'] for el in other_diets if el['other_diet']]) | ||
} | ||
) | ||
|
||
|
||
class AppStats(IsOrganizerMixin, TabsView): | ||
template_name = 'application_stats.html' | ||
|
||
def get_context_data(self, **kwargs): | ||
return {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters