From 7fb035c061741324e3531e01347f3f366e253a3a Mon Sep 17 00:00:00 2001 From: Ryan Cross Date: Mon, 3 Apr 2017 20:36:39 +0000 Subject: [PATCH 1/2] Add Registration models - Legacy-Id: 13182 --- ietf/stats/models.py | 21 +++++++++++++++++++++ ietf/stats/tests.py | 16 ++++++++++++++++ ietf/stats/utils.py | 27 ++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/ietf/stats/models.py b/ietf/stats/models.py index 9aa919b46..df38692de 100644 --- a/ietf/stats/models.py +++ b/ietf/stats/models.py @@ -1,5 +1,8 @@ from django.db import models +from ietf.meeting.models import Meeting from ietf.name.models import CountryName +from ietf.person.models import Person + class AffiliationAlias(models.Model): """Records that alias should be treated as name for statistical @@ -39,3 +42,21 @@ class CountryAlias(models.Model): class Meta: verbose_name_plural = "country aliases" +class Registration(models.Model): + """Registration attendee records from the IETF registration system""" + meeting = models.ForeignKey(Meeting) + first_name = models.CharField(max_length=255) + last_name = models.CharField(max_length=255) + affiliation = models.CharField(blank=True, max_length=255) + country = models.CharField(max_length=2) # ISO 3166 + person = models.ForeignKey(Person, blank=True, null=True) + + def __unicode__(self): + return u"{} {}".format(self.first_name, self.last_name) + +class RegistrationStats(models.Model): + """Statistics from the IETF registration system""" + meeting = models.ForeignKey(Meeting) + gender_male = models.IntegerField(default=0) + gender_female = models.IntegerField(default=0) + gender_undeclared = models.IntegerField(default=0) diff --git a/ietf/stats/tests.py b/ietf/stats/tests.py index ec30ab228..c306a6e6e 100644 --- a/ietf/stats/tests.py +++ b/ietf/stats/tests.py @@ -1,15 +1,20 @@ import datetime +from mock import patch from pyquery import PyQuery +from requests import Response 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 Registration +from ietf.stats.utils import get_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 @@ -147,3 +152,14 @@ class StatisticsTests(TestCase): self.assertEqual(r.status_code, 200) q = PyQuery(r.content) self.assertTrue(q('.review-stats td:contains("1")')) + + @patch('requests.get') + def test_get_registration_data(self, mock_get): + response = Response() + response.status_code = 200 + response._content = '[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]' + mock_get.return_value = response + meeting = MeetingFactory(type_id='ietf', date=datetime.date(2016,7,14), number="96") + get_registration_data(meeting) + query = Registration.objects.filter(first_name='John',last_name='Smith',country='US') + self.assertTrue(query.count(),1) \ No newline at end of file diff --git a/ietf/stats/utils.py b/ietf/stats/utils.py index 1108417f7..3559a15dd 100644 --- a/ietf/stats/utils.py +++ b/ietf/stats/utils.py @@ -1,7 +1,10 @@ import re +import requests from collections import defaultdict -from ietf.stats.models import AffiliationAlias, AffiliationIgnoredEnding, CountryAlias +from django.conf import settings + +from ietf.stats.models import AffiliationAlias, AffiliationIgnoredEnding, CountryAlias, Registration from ietf.name.models import CountryName def compile_affiliation_ending_stripping_regexp(): @@ -205,3 +208,25 @@ def compute_hirsch_index(citation_counts): i += 1 return i + + +def get_registration_data(meeting): + """"Retrieve registration attendee data and summary statistics. Returns number + of Registration records created.""" + num_created = 0 + response = requests.get(settings.REGISTRATION_ATTENDEES_BASE_URL + meeting.number) + if response.status_code == 200: + for registration in response.json(): + object, created = Registration.objects.get_or_create( + meeting=meeting, + first_name=registration['FirstName'], + last_name=registration['LastName'], + affiliation=registration['Company'], + country=registration['Country']) + if created: + num_created += 1 + return num_created + + + + \ No newline at end of file From 304d04e674650a4cb2d2c1a92e03f51bd03bfb0d Mon Sep 17 00:00:00 2001 From: Ryan Cross Date: Tue, 4 Apr 2017 22:06:17 +0000 Subject: [PATCH 2/2] Add Registration migrations - Legacy-Id: 13184 --- .../0003_registration_registrationstats.py | 40 +++++++++++++++++++ .../migrations/0004_import_registrations.py | 28 +++++++++++++ ietf/stats/utils.py | 2 +- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 ietf/stats/migrations/0003_registration_registrationstats.py create mode 100644 ietf/stats/migrations/0004_import_registrations.py diff --git a/ietf/stats/migrations/0003_registration_registrationstats.py b/ietf/stats/migrations/0003_registration_registrationstats.py new file mode 100644 index 000000000..86523fc8d --- /dev/null +++ b/ietf/stats/migrations/0003_registration_registrationstats.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.6 on 2017-03-30 14:38 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('person', '0015_clean_primary'), + ('meeting', '0048_auto_20170330_1438'), + ('stats', '0002_add_initial_aliases'), + ] + + operations = [ + migrations.CreateModel( + name='Registration', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=255)), + ('last_name', models.CharField(max_length=255)), + ('affiliation', models.CharField(blank=True, max_length=255)), + ('country', models.CharField(max_length=2)), + ('meeting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='meeting.Meeting')), + ('person', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='person.Person')), + ], + ), + migrations.CreateModel( + name='RegistrationStats', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('gender_male', models.IntegerField(default=0)), + ('gender_female', models.IntegerField(default=0)), + ('gender_undeclared', models.IntegerField(default=0)), + ('meeting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='meeting.Meeting')), + ], + ), + ] diff --git a/ietf/stats/migrations/0004_import_registrations.py b/ietf/stats/migrations/0004_import_registrations.py new file mode 100644 index 000000000..6347ec64e --- /dev/null +++ b/ietf/stats/migrations/0004_import_registrations.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.6 on 2017-04-04 13:55 +from __future__ import unicode_literals + +from django.db import migrations + +from ietf.stats.utils import get_registration_data + +def forward(apps, schema_editor): + Registration = apps.get_model('stats', 'Registration') + Meeting = apps.get_model('meeting', 'Meeting') + for meeting in Meeting.objects.filter(number__in=[ str(n) for n in range(72,99) ]): + total = get_registration_data(meeting) + print "Meeting {}: {}".format(meeting.number, total) + +def backward(apps, schema_editor): + Registration = apps.get_model('stats', 'Registration') + Registration.objects.all().delete() + +class Migration(migrations.Migration): + + dependencies = [ + ('stats', '0003_registration_registrationstats'), + ] + + operations = [ + migrations.RunPython(forward, backward) + ] diff --git a/ietf/stats/utils.py b/ietf/stats/utils.py index 3559a15dd..27f043ef9 100644 --- a/ietf/stats/utils.py +++ b/ietf/stats/utils.py @@ -218,7 +218,7 @@ def get_registration_data(meeting): if response.status_code == 200: for registration in response.json(): object, created = Registration.objects.get_or_create( - meeting=meeting, + meeting_id=meeting.pk, first_name=registration['FirstName'], last_name=registration['LastName'], affiliation=registration['Company'],