From aff12f708ac0bb0dd2ce2ac6ff08e36500c8510e Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 5 May 2017 10:33:56 +0000 Subject: [PATCH] Add registration country pie chart for to present at the meeting, add meeting stats test, fix a couple of bugs - Legacy-Id: 13267 --- ietf/static/ietf/js/stats.js | 4 ++ ietf/stats/resources.py | 19 ++++++++- ietf/stats/tests.py | 42 +++++++++++++++++-- ietf/stats/views.py | 15 +++++-- ietf/templates/stats/document_stats.html | 2 +- .../stats/meeting_stats_country.html | 34 ++++++++++++++- 6 files changed, 106 insertions(+), 10 deletions(-) diff --git a/ietf/static/ietf/js/stats.js b/ietf/static/ietf/js/stats.js index e62901a20..7dce132d0 100644 --- a/ietf/static/ietf/js/stats.js +++ b/ietf/static/ietf/js/stats.js @@ -14,6 +14,10 @@ $(document).ready(function () { var chart = Highcharts.chart('chart', window.chartConf); } + + if (window.pieChartConf) { + var pieChart = Highcharts.chart('pie-chart', window.pieChartConf); + } /* $(".popover-details").each(function () { var stdNameRegExp = new RegExp("^(rfc|bcp|fyi|std)[0-9]+$", 'i'); diff --git a/ietf/stats/resources.py b/ietf/stats/resources.py index 7b7d354e5..979863762 100644 --- a/ietf/stats/resources.py +++ b/ietf/stats/resources.py @@ -7,7 +7,7 @@ from tastypie.cache import SimpleCache from ietf import api from ietf.api import ToOneField # pyflakes:ignore -from ietf.stats.models import CountryAlias, AffiliationIgnoredEnding, AffiliationAlias +from ietf.stats.models import CountryAlias, AffiliationIgnoredEnding, AffiliationAlias, MeetingRegistration from ietf.name.resources import CountryNameResource @@ -50,3 +50,20 @@ class AffiliationAliasResource(ModelResource): } api.stats.register(AffiliationAliasResource()) +class MeetingRegistrationResource(ModelResource): + class Meta: + queryset = MeetingRegistration.objects.all() + serializer = api.Serializer() + cache = SimpleCache() + #resource_name = 'meetingregistration' + filtering = { + "id": ALL, + "meeting": ALL_WITH_RELATIONS, + "first_name": ALL, + "last_name": ALL, + "affiliation": ALL, + "country_code": ALL, + "person": ALL_WITH_RELATIONS + } +api.stats.register(MeetingRegistrationResource()) + diff --git a/ietf/stats/tests.py b/ietf/stats/tests.py index 82af2e3a3..1fbc2c70c 100644 --- a/ietf/stats/tests.py +++ b/ietf/stats/tests.py @@ -8,15 +8,15 @@ from django.urls import reverse as urlreverse from ietf.utils.test_data import make_test_data, make_review_data from ietf.utils.test_utils import login_testing_unauthorized, TestCase, unicontent -from ietf.stats.models import MeetingRegistration -from ietf.stats.utils import get_meeting_registration_data import ietf.stats.views from ietf.submit.models import Submission from ietf.doc.models import Document, DocAlias, State, RelatedDocument, NewRevisionDocEvent from ietf.meeting.factories import MeetingFactory from ietf.person.models import Person -from ietf.name.models import FormalLanguageName, DocRelationshipName +from ietf.name.models import FormalLanguageName, DocRelationshipName, CountryName +from ietf.stats.models import MeetingRegistration, CountryAlias +from ietf.stats.utils import get_meeting_registration_data class StatisticsTests(TestCase): def test_stats_index(self): @@ -98,6 +98,42 @@ class StatisticsTests(TestCase): if not stats_type.startswith("yearly"): self.assertTrue(q('table.stats-data')) + def test_meeting_stats(self): + # create some data for the statistics + make_test_data() + meeting = MeetingFactory(type_id='ietf', date=datetime.date.today(), number="96") + MeetingRegistration.objects.create(first_name='John', last_name='Smith', country_code='US', meeting=meeting) + CountryAlias.objects.get_or_create(alias="US", country=CountryName.objects.get(slug="US")) + MeetingRegistration.objects.create(first_name='Jaume', last_name='Guillaume', country_code='FR', meeting=meeting) + CountryAlias.objects.get_or_create(alias="FR", country=CountryName.objects.get(slug="FR")) + + # check redirect + url = urlreverse(ietf.stats.views.meeting_stats) + + authors_url = urlreverse(ietf.stats.views.meeting_stats, kwargs={ "stats_type": "overview" }) + + r = self.client.get(url) + self.assertEqual(r.status_code, 302) + self.assertTrue(authors_url in r["Location"]) + + # check various stats types + for stats_type in ["overview", "country", "continent"]: + url = urlreverse(ietf.stats.views.meeting_stats, kwargs={ "stats_type": stats_type }) + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertTrue(q('#chart')) + if stats_type == "overview": + self.assertTrue(q('table.stats-data')) + + for stats_type in ["country", "continent"]: + url = urlreverse(ietf.stats.views.meeting_stats, kwargs={ "stats_type": stats_type, "num": meeting.number }) + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertTrue(q('#chart')) + self.assertTrue(q('table.stats-data')) + def test_known_country_list(self): make_test_data() diff --git a/ietf/stats/views.py b/ietf/stats/views.py index 96b68fb4a..cfcd13501 100644 --- a/ietf/stats/views.py +++ b/ietf/stats/views.py @@ -766,6 +766,7 @@ def meeting_stats(request, num=None, stats_type=None): return HttpResponseRedirect(build_meeting_stats_url(number=num, stats_type_override=possible_stats_types[0][0])) chart_data = [] + piechart_data = [] table_data = [] stats_title = "" template_name = stats_type @@ -795,7 +796,7 @@ def meeting_stats(request, num=None, stats_type=None): for r in registrations: name = (r.first_name + " " + r.last_name).strip() c = country_mapping.get(r.country_code) - bins[c.name if c else None].add(name) + bins[c.name if c else ""].add(name) if c and c.in_eu: bins[eu_name].add(name) @@ -810,8 +811,15 @@ def meeting_stats(request, num=None, stats_type=None): series_data.append((country, len(names))) table_data.append((country, percentage, names)) + if country and country != eu_name: + piechart_data.append({ "name": country, "y": percentage }) + series_data.sort(key=lambda t: t[1], reverse=True) - series_data = series_data[:30] + series_data = series_data[:20] + + piechart_data.sort(key=lambda d: d["y"], reverse=True) + pie_cut_off = 8 + piechart_data = piechart_data[:pie_cut_off] + [{ "name": "Other", "y": sum(d["y"] for d in piechart_data[pie_cut_off:])}] chart_data.append({ "data": series_data }) @@ -825,7 +833,7 @@ def meeting_stats(request, num=None, stats_type=None): for r in registrations: name = (r.first_name + " " + r.last_name).strip() c = country_mapping.get(r.country_code) - bins[c.continent.name if c else None].add(name) + bins[c.continent.name if c else ""].add(name) prune_unknown_bin_with_known(bins) total_registrations = count_bins(bins) @@ -916,6 +924,7 @@ def meeting_stats(request, num=None, stats_type=None): return render(request, "stats/meeting_stats.html", { "chart_data": mark_safe(json.dumps(chart_data)), + "piechart_data": mark_safe(json.dumps(piechart_data)), "table_data": table_data, "stats_title": stats_title, "possible_stats_types": possible_stats_types, diff --git a/ietf/templates/stats/document_stats.html b/ietf/templates/stats/document_stats.html index 18eb1ee9c..a3819d9e5 100644 --- a/ietf/templates/stats/document_stats.html +++ b/ietf/templates/stats/document_stats.html @@ -74,5 +74,5 @@ - + {% endblock %} diff --git a/ietf/templates/stats/meeting_stats_country.html b/ietf/templates/stats/meeting_stats_country.html index 22f853079..dc42e0086 100644 --- a/ietf/templates/stats/meeting_stats_country.html +++ b/ietf/templates/stats/meeting_stats_country.html @@ -42,6 +42,36 @@ }; +
+ + +

Data

@@ -65,5 +95,5 @@

EU (European Union) is not a country, but has been added for reference, as the sum of all current EU member countries: - {% for c in eu_countries %}{{ c.name }}{% if not forloop.last %}, {% endif %}{% endfor %}.

- + {% for c in eu_countries %}{{ c.name }}{% if not forloop.last %}, {% endif %}{% endfor %}. +