From 75dbe017a62eb776df86bc1b1a135bc93519fae4 Mon Sep 17 00:00:00 2001 From: Tero Kivinen Date: Tue, 20 Mar 2018 17:28:48 +0000 Subject: [PATCH] Backfilled IETF meetings starting from 1 and backfilled the attendee numbers for them. Modified the overview attendee statistics page to use different colors for different venue continents. Commit ready for merge. - Legacy-Id: 14879 --- .../migrations/0004_meeting_attendees.py | 20 ++++ .../migrations/0005_backfill_old_meetings.py | 85 ++++++++++++++++ .../migrations/0006_backfill_attendees.py | 97 +++++++++++++++++++ ietf/meeting/models.py | 2 + ietf/secr/meetings/tests.py | 3 + ietf/static/ietf/css/ietf.css | 4 + ietf/stats/views.py | 53 +++++++--- ietf/templates/stats/document_stats.html | 2 + ietf/templates/stats/meeting_stats.html | 2 + .../stats/meeting_stats_continent.html | 2 +- .../stats/meeting_stats_country.html | 2 +- .../stats/meeting_stats_overview.html | 94 ++++++++++++++---- 12 files changed, 335 insertions(+), 31 deletions(-) create mode 100644 ietf/meeting/migrations/0004_meeting_attendees.py create mode 100644 ietf/meeting/migrations/0005_backfill_old_meetings.py create mode 100644 ietf/meeting/migrations/0006_backfill_attendees.py diff --git a/ietf/meeting/migrations/0004_meeting_attendees.py b/ietf/meeting/migrations/0004_meeting_attendees.py new file mode 100644 index 000000000..2646f69e3 --- /dev/null +++ b/ietf/meeting/migrations/0004_meeting_attendees.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.11 on 2018-03-20 09:17 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('meeting', '0003_rename_modified_fields'), + ] + + operations = [ + migrations.AddField( + model_name='meeting', + name='attendees', + field=models.IntegerField(blank=True, default=0, help_text='Number of Attendees for backfilled meetings, leave it to 0 for new meetings, and then it is calculated from the registrations'), + ), + ] diff --git a/ietf/meeting/migrations/0005_backfill_old_meetings.py b/ietf/meeting/migrations/0005_backfill_old_meetings.py new file mode 100644 index 000000000..38959f5aa --- /dev/null +++ b/ietf/meeting/migrations/0005_backfill_old_meetings.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +def backfill_old_meetings(apps, schema_editor): + Meeting = apps.get_model('meeting', 'Meeting') + + for id, number, type_id, date, city, country, time_zone, continent, attendees in [ + ( 59,'59','ietf','2004-03-29','Seoul','KR','Asia/Seoul','Asia','1390' ), + ( 58,'58','ietf','2003-11-09','Minneapolis','US','America/Menominee','America','1233' ), + ( 57,'57','ietf','2003-07-13','Vienna','AT','Europe/Vienna','Europe','1304' ), + ( 56,'56','ietf','2003-03-16','San Francisco','US','America/Los_Angeles','America','1679' ), + ( 55,'55','ietf','2002-11-17','Atlanta','US','America/New_York','America','1570' ), + ( 54,'54','ietf','2002-07-14','Yokohama','JP','Asia/Tokyo','Asia','1885' ), + ( 53,'53','ietf','2002-03-17','Minneapolis','US','America/Menominee','America','1656' ), + ( 52,'52','ietf','2001-12-09','Salt Lake City','US','America/Denver','America','1691' ), + ( 51,'51','ietf','2001-08-05','London','GB','Europe/London','Europe','2226' ), + ( 50,'50','ietf','2001-03-18','Minneapolis','US','America/Menominee','America','1822' ), + ( 49,'49','ietf','2000-12-10','San Diego','US','America/Los_Angeles','America','2810' ), + ( 48,'48','ietf','2000-07-31','Pittsburgh','US','America/New_York','America','2344' ), + ( 47,'47','ietf','2000-03-26','Adelaide','AU','Australia/Adelaide','Australia','1431' ), + ( 46,'46','ietf','1999-11-07','Washington','US','America/New_York','America','2379' ), + ( 45,'45','ietf','1999-07-11','Oslo','NO','Europe/Oslo','Europe','1710' ), + ( 44,'44','ietf','1999-03-14','Minneapolis','US','America/Menominee','America','1705' ), + ( 43,'43','ietf','1998-12-07','Orlando','US','America/New_York','America','2124' ), + ( 42,'42','ietf','1998-08-24','Chicago','US','America/Chicago','America','2106' ), + ( 41,'41','ietf','1998-03-30','Los Angeles','US','America/Los_Angeles','America','1775' ), + ( 40,'40','ietf','1997-12-08','Washington','US','America/New_York','America','1897' ), + ( 39,'39','ietf','1997-08-11','Munich','DE','Europe/Berlin','Europe','1308' ), + ( 38,'38','ietf','1997-04-07','Memphis','US','America/Chicago','America','1321' ), + ( 37,'37','ietf','1996-12-09','San Jose','US','America/Los_Angeles','America','1993' ), + ( 36,'36','ietf','1996-06-24','Montreal','CA','America/New_York','America','1283' ), + ( 35,'35','ietf','1996-03-04','Los Angeles','US','America/Los_Angeles','America','1038' ), + ( 34,'34','ietf','1995-12-04','Dallas','US','America/Chicago','America','1007' ), + ( 33,'33','ietf','1995-07-17','Stockholm','SE','Europe/Stockholm','Europe','617' ), + ( 32,'32','ietf','1995-04-03','Danvers','US','America/New_York','America','983' ), + ( 31,'31','ietf','1994-12-05','San Jose','US','America/Los_Angeles','America','1079' ), + ( 30,'30','ietf','1994-07-25','Toronto','CA','America/New_York','America','710' ), + ( 29,'29','ietf','1994-03-28','Seattle','US','America/Los_Angeles','America','785' ), + ( 28,'28','ietf','1993-11-01','Houston','US','America/Chicago','America','636' ), + ( 27,'27','ietf','1993-07-12','Amsterdam','NL','Europe/Amsterdam','Europe','493' ), + ( 26,'26','ietf','1993-03-29','Columbus','US','America/New_York','America','638' ), + ( 25,'25','ietf','1992-11-16','Washington','US','America/New_York','America','633' ), + ( 24,'24','ietf','1992-07-13','Cambridge','US','America/New_York','America','677' ), + ( 23,'23','ietf','1992-03-16','San Diego','US','America/Los_Angeles','America','530' ), + ( 22,'22','ietf','1991-11-18','Santa Fe','US','America/Denver','America','372' ), + ( 21,'21','ietf','1991-07-29','Atlanta','US','America/New_York','America','387' ), + ( 20,'20','ietf','1991-03-11','St. Louis','US','America/Chicago','America','348' ), + ( 19,'19','ietf','1990-12-03','Boulder','US','America/Denver','America','292' ), + ( 18,'18','ietf','1990-07-30','Vancouver','CA','America/Los_Angeles','America','293' ), + ( 17,'17','ietf','1990-05-01','Pittsburgh','US','America/New_York','America','244' ), + ( 16,'16','ietf','1990-02-06','Tallahassee','US','America/New_York','America','196' ), + ( 15,'15','ietf','1989-10-31','Honolulu','US','Pacific/Honolulu','America','138' ), + ( 14,'14','ietf','1989-07-25','Stanford','US','America/Los_Angeles','America','217' ), + ( 13,'13','ietf','1989-04-11','Cocoa Beach','US','America/New_York','America','114' ), + ( 12,'12','ietf','1989-01-18','Austin','US','America/Chicago','America','120' ), + ( 11,'11','ietf','1988-10-17','Ann Arbor','US','America/New_York','America','114' ), + ( 10,'10','ietf','1988-06-15','Annapolis','US','America/New_York','America','112' ), + ( 9,'9','ietf','1988-03-01','San Diego','US','America/Los_Angeles','America','82' ), + ( 8,'8','ietf','1987-11-02','Boulder','US','America/Denver','America','56' ), + ( 7,'7','ietf','1987-07-27','McLean','US','America/New_York','America','101' ), + ( 6,'6','ietf','1987-04-22','Boston','US','America/New_York','America','88' ), + ( 5,'5','ietf','1987-02-04','Moffett Field','US','America/Los_Angeles','America','35' ), + ( 4,'4','ietf','1986-10-15','Menlo Park','US','America/Los_Angeles','America','35' ), + ( 3,'3','ietf','1986-07-23','Ann Arbor','US','America/New_York','America','18' ), + ( 2,'2','ietf','1986-04-08','Aberdeen','US','America/New_York','America','21' ), + ( 1,'1','ietf','1986-01-16','San Diego','US','America/Los_Angeles','America','21' ), + ]: + Meeting.objects.get_or_create(id=id, number=number, type_id=type_id, + date=date, city=city, country=country, + time_zone=time_zone); + + +class Migration(migrations.Migration): + + dependencies = [ + ('meeting', '0004_meeting_attendees'), + ] + + operations = [ + migrations.RunPython(backfill_old_meetings) + ] + diff --git a/ietf/meeting/migrations/0006_backfill_attendees.py b/ietf/meeting/migrations/0006_backfill_attendees.py new file mode 100644 index 000000000..52a1dac25 --- /dev/null +++ b/ietf/meeting/migrations/0006_backfill_attendees.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +def backfill_old_meetings(apps, schema_editor): + Meeting = apps.get_model('meeting', 'Meeting') + + for number, attendees in [ + ( 71,1174 ), + ( 70,1128 ), + ( 69,1175 ), + ( 68,1193 ), + ( 67,1245 ), + ( 66,1257 ), + ( 65,1264 ), + ( 64,1240 ), + ( 63,1450 ), + ( 62,1133 ), + ( 61,1311 ), + ( 60,1460 ), + ( 59,1390 ), + ( 58,1233 ), + ( 57,1304 ), + ( 56,1679 ), + ( 55,1570 ), + ( 54,1885 ), + ( 53,1656 ), + ( 52,1691 ), + ( 51,2226 ), + ( 50,1822 ), + ( 49,2810 ), + ( 48,2344 ), + ( 47,1431 ), + ( 46,2379 ), + ( 45,1710 ), + ( 44,1705 ), + ( 43,2124 ), + ( 42,2106 ), + ( 41,1775 ), + ( 40,1897 ), + ( 39,1308 ), + ( 38,1321 ), + ( 37,1993 ), + ( 36,1283 ), + ( 35,1038 ), + ( 34,1007 ), + ( 33,617 ), + ( 32,983 ), + ( 31,1079 ), + ( 30,710 ), + ( 29,785 ), + ( 28,636 ), + ( 27,493 ), + ( 26,638 ), + ( 25,633 ), + ( 24,677 ), + ( 23,530 ), + ( 22,372 ), + ( 21,387 ), + ( 20,348 ), + ( 19,292 ), + ( 18,293 ), + ( 17,244 ), + ( 16,196 ), + ( 15,138 ), + ( 14,217 ), + ( 13,114 ), + ( 12,120 ), + ( 11,114 ), + ( 10,112 ), + ( 9,82 ), + ( 8,56 ), + ( 7,101 ), + ( 6,88 ), + ( 5,35 ), + ( 4,35 ), + ( 3,18 ), + ( 2,21 ), + ( 1,21 ), + ]: + meeting = Meeting.objects.filter(type='ietf', + number=number).first(); + meeting.attendees = attendees + meeting.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('meeting', '0005_backfill_old_meetings'), + ] + + operations = [ + migrations.RunPython(backfill_old_meetings) + ] + diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index 014a500d6..32e318662 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -95,6 +95,8 @@ class Meeting(models.Model): acknowledgements = models.TextField(blank=True, help_text="Acknowledgements for use in meeting proceedings. Use ReStructuredText markup.") overview = ForeignKey(DBTemplate, related_name='overview', null=True, editable=False) show_important_dates = models.BooleanField(default=False) + attendees = models.IntegerField(blank=True, default=0, + help_text=u"Number of Attendees for backfilled meetings, leave it to 0 for new meetings, and then it is calculated from the registrations") def __unicode__(self): if self.type_id == "ietf": diff --git a/ietf/secr/meetings/tests.py b/ietf/secr/meetings/tests.py index 122f136f2..2d58936e0 100644 --- a/ietf/secr/meetings/tests.py +++ b/ietf/secr/meetings/tests.py @@ -98,6 +98,7 @@ class SecrMeetingTestCase(TestCase): meeting.agenda.assignments.filter(timeslot__type='reg').count(), new_meeting.agenda.assignments.filter(timeslot__type='reg').count() ) + self.assertEqual(new_meeting.attendees,0) def test_edit_meeting(self): "Edit Meeting" @@ -115,12 +116,14 @@ class SecrMeetingTestCase(TestCase): submission_start_day_offset=90, submission_cutoff_day_offset=26, submission_correction_day_offset=50, + attendees=1234, ) self.client.login(username="secretary", password="secretary+password") response = self.client.post(url, post_data,follow=True) self.assertEqual(response.status_code, 200) meeting = Meeting.objects.get(number=1) self.assertEqual(meeting.city,'Toronto') + self.assertEqual(meeting.attendees,1234) def test_blue_sheets_upload(self): "Test Bluesheets" diff --git a/ietf/static/ietf/css/ietf.css b/ietf/static/ietf/css/ietf.css index 2259f605c..fcf106067 100644 --- a/ietf/static/ietf/css/ietf.css +++ b/ietf/static/ietf/css/ietf.css @@ -614,6 +614,10 @@ table.simple-table td:last-child { height: 25em; } +.document-stats #chart.chart-overview { + height: 35em; +} + .stats-time-graph { height: 15em; } diff --git a/ietf/stats/views.py b/ietf/stats/views.py index c9bef3606..939594b6f 100644 --- a/ietf/stats/views.py +++ b/ietf/stats/views.py @@ -882,28 +882,57 @@ def meeting_stats(request, num=None, stats_type=None): if stats_type == "overview": stats_title = "Number of attendees per meeting" + meetings = {} + continents = {} + + for m in Meeting.objects.filter(type='ietf').order_by('number'): + meeting_number = int(m.number) + meetings[meeting_number] = m + country = CountryName.objects.get(slug=m.country) + continents[country.continent.name] = country.continent.name + bins = defaultdict(set) for r in attendees: meeting_number = int(r.meeting.number) name = reg_name(r) - bins[meeting_number].add(name) - - meeting_cities = dict(Meeting.objects.filter(number__in=bins.iterkeys()).values_list("number", "city")) - - series_data = [] + for meeting_number, names in sorted(bins.iteritems()): - series_data.append((meeting_number, len(names))) - url = build_meeting_stats_url(number=meeting_number, stats_type_override="country") - label = "IETF {} - {}".format(meeting_number, meeting_cities.get(str(meeting_number), "")) - table_data.append((meeting_number, label, url, len(names), list(names)[:names_limit])) + meetings[meeting_number].attendees = len(names) - series_data.sort(key=lambda t: t[0]) - table_data.sort(key=lambda t: t[0], reverse=True) + series_data = {} + for continent in continents.keys(): + series_data[continent] = [] - chart_data.append({ "name": "Attendees", "data": series_data }) + for m in meetings: + meeting = meetings[m] + country = CountryName.objects.get(slug=meeting.country) + url = build_meeting_stats_url(number=meeting.number, + stats_type_override="country") + for continent in continents.keys(): + if continent == country.continent.name: + d = { + "name": "IETF {} - {}, {}".format(int(meeting.number), meeting.city, country), + "x": int(meeting.number), + "y": meeting.attendees, + "url": url, + } + else: + d = { + "x": int(meeting.number), + "y": 0, + } + series_data[continent].append(d) + table_data.append((meeting, url, + meeting.attendees, country)) + for continent in continents.keys(): +# series_data[continent].sort(key=lambda t: t[0]["x"]) + chart_data.append( { "name": continent, + "data": series_data[continent] }) + + table_data.sort(key=lambda t: int(t[0].number), reverse=True) elif stats_type == "country": stats_title = "Number of attendees per country across meetings" diff --git a/ietf/templates/stats/document_stats.html b/ietf/templates/stats/document_stats.html index a3819d9e5..855d75f8d 100644 --- a/ietf/templates/stats/document_stats.html +++ b/ietf/templates/stats/document_stats.html @@ -8,6 +8,7 @@ {% block pagehead %} + {% endblock %} {% block content %} @@ -75,4 +76,5 @@ + {% endblock %} diff --git a/ietf/templates/stats/meeting_stats.html b/ietf/templates/stats/meeting_stats.html index c79c67e57..695273b6f 100644 --- a/ietf/templates/stats/meeting_stats.html +++ b/ietf/templates/stats/meeting_stats.html @@ -8,6 +8,7 @@ {% block pagehead %} + {% endblock %} {% block content %} @@ -43,4 +44,5 @@ + {% endblock %} diff --git a/ietf/templates/stats/meeting_stats_continent.html b/ietf/templates/stats/meeting_stats_continent.html index 3ef272fc6..f7a764f65 100644 --- a/ietf/templates/stats/meeting_stats_continent.html +++ b/ietf/templates/stats/meeting_stats_continent.html @@ -44,7 +44,7 @@

Data

- +
diff --git a/ietf/templates/stats/meeting_stats_country.html b/ietf/templates/stats/meeting_stats_country.html index 1940b82e9..2219bef2d 100644 --- a/ietf/templates/stats/meeting_stats_country.html +++ b/ietf/templates/stats/meeting_stats_country.html @@ -74,7 +74,7 @@

Data

-
Continent
+
diff --git a/ietf/templates/stats/meeting_stats_overview.html b/ietf/templates/stats/meeting_stats_overview.html index 821767843..e9f7d52da 100644 --- a/ietf/templates/stats/meeting_stats_overview.html +++ b/ietf/templates/stats/meeting_stats_overview.html @@ -1,9 +1,59 @@

{{ stats_title }}

-
+ +
@@ -57,17 +109,25 @@ {% if table_data %}

Data

-
Country
+
+ + + + - {% for meeting_number, label, url, count, names in table_data %} + {% for meeting, url, count, country in table_data %} - + + + + + {% endfor %}
MeetingDateCityCountryContinent Attendees
{{ label }}{{ meeting.number }}{{ meeting.date }} {{ meeting.city }}{{ country.name }}{{ country.continent }} {% include "stats/includes/number_with_details_cell.html" %}