From 06f6b12b185864b38594a60627ef59496844c26b Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Tue, 22 Jun 2021 20:09:40 +0000 Subject: [PATCH] Refine volunteer list view. Show rfc8989 paths. Commit ready for merge. - Legacy-Id: 19139 --- ietf/nomcom/tests.py | 49 ++++++++++++++++++++++++++- ietf/nomcom/utils.py | 37 ++++++++++++++++---- ietf/nomcom/views.py | 2 ++ ietf/templates/nomcom/volunteers.html | 47 +++++++++++++++---------- 4 files changed, 109 insertions(+), 26 deletions(-) diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index acf6036e7..7b78d042f 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -41,7 +41,8 @@ from ietf.nomcom.factories import NomComFactory, FeedbackFactory, TopicFactory, key from ietf.nomcom.utils import get_nomcom_by_year, make_nomineeposition, \ get_hash_nominee_position, is_eligible, list_eligible, \ - get_eligibility_date, suggest_affiliation + get_eligibility_date, suggest_affiliation, \ + decorate_volunteers_with_qualifications from ietf.person.factories import PersonFactory, EmailFactory from ietf.person.models import Email, Person from ietf.stats.models import MeetingRegistration @@ -2529,3 +2530,49 @@ class VolunteerTests(TestCase): self.assertEqual(suggest_affiliation(person), 'volunteer_affil') MeetingRegistrationFactory(person=person, affiliation='meeting_affil') self.assertEqual(suggest_affiliation(person), 'meeting_affil') + +class VolunteerDecoratorUnitTests(TestCase): + def test_decorate_volunteers_with_qualifications(self): + nomcom = NomComFactory(group__acronym='nomcom2021', populate_personnel=False, first_call_for_volunteers=datetime.date(2021,5,15)) + elig_date = get_eligibility_date(nomcom) + Role.objects.filter(name_id__in=('chair','secr')).delete() + + meeting_person = PersonFactory() + meetings = [MeetingFactory(number=number, date=date, type_id='ietf') for number,date in [ + ('110', datetime.date(2021, 3, 6)), + ('109', datetime.date(2020, 11, 14)), + ('108', datetime.date(2020, 7, 25)), + ('107', datetime.date(2020, 3, 21)), + ('106', datetime.date(2019, 11, 16)), + ]] + for m in meetings: + MeetingRegistrationFactory(meeting=m,person=meeting_person) + nomcom.volunteer_set.create(person=meeting_person) + + office_person = PersonFactory() + RoleHistoryFactory( + name_id='chair', + group__time= elig_date - datetime.timedelta(days=365), + group__group__state_id='conclude', + person=office_person, + ) + nomcom.volunteer_set.create(person=office_person) + + author_person = PersonFactory() + for i in range(2): + da = WgDocumentAuthorFactory(person=author_person) + DocEventFactory(type='published_rfc',doc=da.document,time=datetime.date(elig_date.year-3,elig_date.month,elig_date.day)) + nomcom.volunteer_set.create(person=author_person) + + volunteers = nomcom.volunteer_set.all() + decorate_volunteers_with_qualifications(volunteers,nomcom=nomcom) + + self.assertEqual(len(volunteers), 3) + for v in volunteers: + if v.person == meeting_person: + self.assertEqual(v.qualifications,'path_1') + if v.person == office_person: + self.assertEqual(v.qualifications,'path_2') + if v.person == author_person: + self.assertEqual(v.qualifications,'path_3') + diff --git a/ietf/nomcom/utils.py b/ietf/nomcom/utils.py index 99ff39321..9413c42fe 100644 --- a/ietf/nomcom/utils.py +++ b/ietf/nomcom/utils.py @@ -500,6 +500,25 @@ def list_eligible(nomcom=None, date=None, base_qs=None): else: return Person.objects.none() +def decorate_volunteers_with_qualifications(volunteers, nomcom=None, date=None, base_qs=None): + if not base_qs: + base_qs = Person.objects.all() + eligibility_date = get_eligibility_date(nomcom, date) + if eligibility_date.year == 2021: + three_of_five_qs, officer_qs, author_qs = get_8989_eligibility_querysets(eligibility_date, base_qs) + for v in volunteers: + qualifications = [] + if v.person in three_of_five_qs: + qualifications.append('path_1') + if v.person in officer_qs: + qualifications.append('path_2') + if v.person in author_qs: + qualifications.append('path_3') + v.qualifications = ", ".join(qualifications) + else: + for v in volunteers: + v.qualifications = '' + def list_eligible_8713(date, base_qs=None): if not base_qs: base_qs = Person.objects.all() @@ -512,7 +531,7 @@ def list_eligible_8788(date, base_qs=None): previous_five = Meeting.objects.filter(number__in=['102','103','104','105','106']) return remove_disqualified(three_of_five_eligible(previous_five=previous_five, queryset=base_qs)) -def list_eligible_8989(date, base_qs=None): +def get_8989_eligibility_querysets(date, base_qs): if not base_qs: base_qs = Person.objects.all() @@ -545,13 +564,17 @@ def list_eligible_8989(date, base_qs=None): ).annotate( document_author_count = Count('documentauthor') ).filter(document_author_count__gte=2) + return three_of_five_qs, officer_qs, author_qs - # Would be nice to use queryset union here, but the annotations make that difficult - return remove_disqualified(Person.objects.filter(pk__in= - set(three_of_five_qs.values_list('pk',flat=True)).union( - set(officer_qs.values_list('pk',flat=True))).union( - set(author_qs.values_list('pk',flat=True))) - )) +def list_eligible_8989(date, base_qs=None): + if not base_qs: + base_qs = Person.objects.all() + three_of_five_qs, officer_qs, author_qs = get_8989_eligibility_querysets(date, base_qs) + # Would be nice to use queryset union here, but the annotations in the three existing querysets make that difficult + three_of_five_pks = three_of_five_qs.values_list('pk',flat=True) + officer_pks = officer_qs.values_list('pk',flat=True) + author_pks = author_qs.values_list('pk',flat=True) + return remove_disqualified(Person.objects.filter(pk__in=set(three_of_five_pks).union(set(officer_pks)).union(set(author_pks)))) def get_eligibility_date(nomcom=None, date=None): if date: diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index a2dfcbc37..5ddeec24d 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -36,6 +36,7 @@ from ietf.nomcom.models import (Position, NomineePosition, Nominee, Feedback, No FeedbackLastSeen, Topic, TopicFeedbackLastSeen, ) from ietf.nomcom.utils import (get_nomcom_by_year, store_nomcom_private_key, suggest_affiliation, get_hash_nominee_position, send_reminder_to_nominees, list_eligible, + decorate_volunteers_with_qualifications, HOME_TEMPLATE, NOMINEE_ACCEPT_REMINDER_TEMPLATE,NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE, ) from ietf.ietfauth.utils import role_required @@ -1323,6 +1324,7 @@ def volunteers(request, year, public=False): eligible = list_eligible(nomcom) for v in volunteers: v.eligible = v.person in eligible + decorate_volunteers_with_qualifications(volunteers,nomcom=nomcom) volunteers = sorted(volunteers,key=lambda v:(not v.eligible,v.person.last_name())) return render(request, 'nomcom/volunteers.html', dict(year=year, nomcom=nomcom, volunteers=volunteers, public=public)) diff --git a/ietf/templates/nomcom/volunteers.html b/ietf/templates/nomcom/volunteers.html index b64036c11..b95bc51dc 100644 --- a/ietf/templates/nomcom/volunteers.html +++ b/ietf/templates/nomcom/volunteers.html @@ -14,25 +14,36 @@ {% origin %}

Volunteers for {{ nomcom.group }}

- - - - - - - - - - {% for v in volunteers %} - - - - - - + {% regroup volunteers by eligible as volunteers_by_eligibility %} + + {% for eligibility_group in volunteers_by_eligibility %} +
+
{{ eligibility_group.grouper|yesno:"Eligible, Not Eligible"}}
+
+
EligibleLast NameFirst NameAffiliationEmail Addresses
{{v.eligible|yesno}} - {{v.person.last_name}}{{v.person.first_name}}{{v.affiliation}}{% for e in v.person.email_set.all %}{{e.address}}{% if not forloop.last %}, {% endif %}{% endfor %}
+ + + + + + + + + + {% for v in eligibility_group.list %} + + + + + + + + + {% endfor %} +
Last NameFirst NameAffiliationPrimary Email AddressQualifications
{{ forloop.counter }}{{v.person.last_name}}{{v.person.first_name}}{{v.affiliation}}{{v.person.email}}{{v.qualifications}}
+ + {% endfor %} - {% endblock nomcom_content %} {% block js %}