connect the new calculations to the UI. Clean flakes.

- Legacy-Id: 18974
This commit is contained in:
Robert Sparks 2021-05-06 19:00:58 +00:00
parent e3476f5bdb
commit fe82f4d696
10 changed files with 27 additions and 74 deletions

View file

@ -13,7 +13,7 @@ from django.conf import settings
from ietf.doc.models import ( Document, DocEvent, NewRevisionDocEvent, DocAlias, State, DocumentAuthor, from ietf.doc.models import ( Document, DocEvent, NewRevisionDocEvent, DocAlias, State, DocumentAuthor,
StateDocEvent, BallotPositionDocEvent, BallotDocEvent, BallotType, IRSGBallotDocEvent, TelechatDocEvent, StateDocEvent, BallotPositionDocEvent, BallotDocEvent, BallotType, IRSGBallotDocEvent, TelechatDocEvent,
DocumentActionHolder, DocumentAuthor) DocumentActionHolder)
from ietf.group.models import Group from ietf.group.models import Group
def draft_name_generator(type_id,group,n): def draft_name_generator(type_id,group,n):

View file

@ -18,12 +18,11 @@ from django.utils.safestring import mark_safe
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.dbtemplate.models import DBTemplate from ietf.dbtemplate.models import DBTemplate
from ietf.meeting.models import Session, Meeting, SchedulingEvent, TimeSlot, Constraint, SchedTimeSessAssignment from ietf.meeting.models import Session, SchedulingEvent, TimeSlot, Constraint, SchedTimeSessAssignment
from ietf.group.models import Group, Role from ietf.group.models import Group
from ietf.group.utils import can_manage_materials from ietf.group.utils import can_manage_materials
from ietf.name.models import SessionStatusName, ConstraintName from ietf.name.models import SessionStatusName, ConstraintName
from ietf.nomcom.utils import DISQUALIFYING_ROLE_QUERY_EXPRESSION from ietf.person.models import Person
from ietf.person.models import Person, Email
from ietf.secr.proceedings.proc_utils import import_audio_files from ietf.secr.proceedings.proc_utils import import_audio_files
def session_time_for_sorting(session, use_meeting_date): def session_time_for_sorting(session, use_meeting_date):
@ -171,25 +170,6 @@ def finalize(meeting):
meeting.save() meeting.save()
return return
def attended_ietf_meetings(person):
email_addresses = Email.objects.filter(person=person).values_list('address',flat=True)
return Meeting.objects.filter(
type='ietf',
meetingregistration__email__in=email_addresses,
meetingregistration__attended=True,
)
def attended_in_last_five_ietf_meetings(person, date=datetime.datetime.today()):
previous_five = Meeting.objects.filter(type='ietf',date__lte=date).order_by('-date')[:5]
attended = attended_ietf_meetings(person)
return set(previous_five).intersection(attended)
def is_nomcom_eligible(person, date=datetime.date.today()):
attended = attended_in_last_five_ietf_meetings(person, date)
disqualifying_roles = Role.objects.filter(person=person).filter(DISQUALIFYING_ROLE_QUERY_EXPRESSION)
return len(attended)>=3 and not disqualifying_roles.exists()
def sort_accept_tuple(accept): def sort_accept_tuple(accept):
tup = [] tup = []
if accept: if accept:

View file

@ -480,6 +480,10 @@ def create_feedback_email(nomcom, msg):
class EncryptedException(Exception): class EncryptedException(Exception):
pass pass
def remove_disqualified(queryset):
disqualified_roles = Role.objects.filter(DISQUALIFYING_ROLE_QUERY_EXPRESSION)
return queryset.exclude(role__in=disqualified_roles)
def is_eligible(person, nomcom=None, date=None): def is_eligible(person, nomcom=None, date=None):
return list_eligible(nomcom=nomcom, date=date, base_qs=Person.objects.filter(pk=person.pk)).exists() return list_eligible(nomcom=nomcom, date=date, base_qs=Person.objects.filter(pk=person.pk)).exists()
@ -500,13 +504,13 @@ def list_eligible_8713(date, base_qs=None):
if not base_qs: if not base_qs:
base_qs = Person.objects.all() base_qs = Person.objects.all()
previous_five = previous_five_meetings(date) previous_five = previous_five_meetings(date)
return three_of_five_eligible(previous_five=previous_five, queryset=base_qs) return remove_disqualified(three_of_five_eligible(previous_five=previous_five, queryset=base_qs))
def list_eligible_8788(date, base_qs=None): def list_eligible_8788(date, base_qs=None):
if not base_qs: if not base_qs:
base_qs = Person.objects.all() base_qs = Person.objects.all()
previous_five = Meeting.objects.filter(number__in=['102','103','104','105','106']) previous_five = Meeting.objects.filter(number__in=['102','103','104','105','106'])
return three_of_five_eligible(previous_five=previous_five, queryset=base_qs) return remove_disqualified(three_of_five_eligible(previous_five=previous_five, queryset=base_qs))
def list_eligible_8989(date, base_qs=None): def list_eligible_8989(date, base_qs=None):
if not base_qs: if not base_qs:
@ -542,12 +546,12 @@ def list_eligible_8989(date, base_qs=None):
document_author_count = Count('documentauthor') document_author_count = Count('documentauthor')
).filter(document_author_count__gte=2) ).filter(document_author_count__gte=2)
# return three_of_five_qs.union(officer_qs, author_qs) # Would be nice to use queryset union here, but the annotations make that difficult
return Person.objects.filter(pk__in= return remove_disqualified(Person.objects.filter(pk__in=
set(three_of_five_qs.values_list('pk',flat=True)).union( set(three_of_five_qs.values_list('pk',flat=True)).union(
set(officer_qs.values_list('pk',flat=True))).union( set(officer_qs.values_list('pk',flat=True))).union(
set(author_qs.values_list('pk',flat=True))) set(author_qs.values_list('pk',flat=True)))
) ))
def get_eligibility_date(nomcom=None, date=None): def get_eligibility_date(nomcom=None, date=None):
if date: if date:

View file

@ -24,7 +24,6 @@ from ietf.dbtemplate.views import group_template_edit, group_template_show
from ietf.name.models import NomineePositionStateName, FeedbackTypeName from ietf.name.models import NomineePositionStateName, FeedbackTypeName
from ietf.group.models import Group, GroupEvent, Role from ietf.group.models import Group, GroupEvent, Role
from ietf.message.models import Message from ietf.message.models import Message
from ietf.meeting.models import Meeting
from ietf.nomcom.decorators import nomcom_private_key_required from ietf.nomcom.decorators import nomcom_private_key_required
from ietf.nomcom.forms import (NominateForm, NominateNewPersonForm, FeedbackForm, QuestionnaireForm, from ietf.nomcom.forms import (NominateForm, NominateNewPersonForm, FeedbackForm, QuestionnaireForm,
@ -36,12 +35,11 @@ from ietf.nomcom.forms import (NominateForm, NominateNewPersonForm, FeedbackForm
from ietf.nomcom.models import (Position, NomineePosition, Nominee, Feedback, NomCom, ReminderDates, from ietf.nomcom.models import (Position, NomineePosition, Nominee, Feedback, NomCom, ReminderDates,
FeedbackLastSeen, Topic, TopicFeedbackLastSeen, ) FeedbackLastSeen, Topic, TopicFeedbackLastSeen, )
from ietf.nomcom.utils import (get_nomcom_by_year, store_nomcom_private_key, from ietf.nomcom.utils import (get_nomcom_by_year, store_nomcom_private_key,
get_hash_nominee_position, send_reminder_to_nominees, get_hash_nominee_position, send_reminder_to_nominees, list_eligible,
HOME_TEMPLATE, NOMINEE_ACCEPT_REMINDER_TEMPLATE,NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE, HOME_TEMPLATE, NOMINEE_ACCEPT_REMINDER_TEMPLATE,NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE, )
DISQUALIFYING_ROLE_QUERY_EXPRESSION)
from ietf.ietfauth.utils import role_required from ietf.ietfauth.utils import role_required
from ietf.person.models import Person from ietf.person.models import Person
from ietf.utils import log
from ietf.utils.response import permission_denied from ietf.utils.response import permission_denied
import debug # pyflakes:ignore import debug # pyflakes:ignore
@ -1275,31 +1273,7 @@ def extract_email_lists(request, year):
def eligible(request, year): def eligible(request, year):
nomcom = get_nomcom_by_year(year) nomcom = get_nomcom_by_year(year)
# This should probably be refined. If the nomcom year is this year, then eligible_persons = list(list_eligible(nomcom=nomcom))
# today's date makes sense; for previous nomcoms, we should probably get
# the date of the announcement of the Call for Volunteers, instead
date = datetime.date.today()
previous_five = ( Meeting.objects.filter(type='ietf',date__lte=date)
.exclude(city='').exclude(city='Virtual')
.order_by('-date')[:5] )
log.assertion("len(previous_five) == 5")
attendees = {}
potentials = set()
for m in previous_five:
registration_emails = m.meetingregistration_set.filter(attended=True).values_list('email',flat=True)
attendees[m] = Person.objects.filter(email__address__in=registration_emails).distinct()
# See RFC8713 section 4.15
disqualified_roles = Role.objects.filter(DISQUALIFYING_ROLE_QUERY_EXPRESSION)
potentials.update(attendees[m].exclude(role__in=disqualified_roles))
eligible_persons = []
for p in potentials:
count = 0
for m in previous_five:
if p in attendees[m]:
count += 1
if count >= 3:
eligible_persons.append(p)
eligible_persons.sort(key=lambda p: p.last_name() ) eligible_persons.sort(key=lambda p: p.last_name() )
return render(request, 'nomcom/eligible.html', return render(request, 'nomcom/eligible.html',

View file

@ -6,14 +6,14 @@ from django import template
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.meeting.utils import is_nomcom_eligible as util_is_nomcom_eligible from ietf.nomcom.utils import is_eligible
from ietf.person.models import Alias from ietf.person.models import Alias
register = template.Library() register = template.Library()
@register.filter @register.filter
def is_nomcom_eligible(person, date=datetime.date.today()): def is_nomcom_eligible(person, date=datetime.date.today()):
return util_is_nomcom_eligible(person,date) return is_eligible(person=person,date=date)
@register.filter @register.filter
def person_by_name(name): def person_by_name(name):

View file

@ -2,7 +2,7 @@
import debug # pyflakes:ignore import debug # pyflakes:ignore
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand
from ietf.stats.utils import find_meetingregistration_person_issues from ietf.stats.utils import find_meetingregistration_person_issues

View file

@ -2,7 +2,7 @@
import debug # pyflakes:ignore import debug # pyflakes:ignore
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand
from ietf.stats.utils import repair_meetingregistration_person from ietf.stats.utils import repair_meetingregistration_person

View file

@ -6,7 +6,6 @@ import re
import requests import requests
from collections import defaultdict from collections import defaultdict
from django.db.models import F, Q
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User

View file

@ -14,9 +14,6 @@
{% origin %} {% origin %}
<h2>Eligible People for {{ nomcom.group }}</h2> <h2>Eligible People for {{ nomcom.group }}</h2>
<p class="alert alert-info">
This calculation is experimental and is likely wrong. Check carefully against the secretariat eligibility tools if it matters. This page lists people who would be nomcom eligible if the selection were made <em>today</em>. Thus if today is not between the spring and summer IETF meetings, the list won't reflect eligibility at the time actual selections will be made.
</p>
<table class="table table-condensed table-striped tablesorter"> <table class="table table-condensed table-striped tablesorter">
<thead> <thead>
<th>Last Name</th> <th>Last Name</th>

View file

@ -69,17 +69,16 @@
<div class="col-sm-1 form-control-static">{{person|is_nomcom_eligible|yesno:'Yes,No,No'}}</div> <div class="col-sm-1 form-control-static">{{person|is_nomcom_eligible|yesno:'Yes,No,No'}}</div>
<div class="col-sm-9"> <div class="col-sm-9">
<p class="alert alert-info form-control-static"> <p class="alert alert-info form-control-static">
This calculation is EXPERIMENTAL.<br/> If you believe this calculation is incorrect, make sure you've added all the
If you believe it is incorrect, make sure you've added all the
email addresses you've registered for IETF meetings with to the email addresses you've registered for IETF meetings with to the
list below.<br/> list below.<br/>
If you've done so and the calculation is still incorrect, please If you've done so and the calculation is still incorrect, please
send a note to send a note to
<a href="mailto:{{settings.SECRETARIAT_INFO_EMAIL}}">{{settings.SECRETARIAT_INFO_EMAIL}}</a>.<br/> <a href="mailto:{{settings.SECRETARIAT_SUPPORT_EMAIL}}">{{settings.SECRETARIAT_SUPPORT_EMAIL}}</a>.<br/>
See <a href="{% url 'ietf.doc.views_doc.document_main' name='rfc7437'%}">RFC 7437</a> See <a href="{% url 'ietf.doc.views_doc.document_main' name='rfc8713'%}">RFC 8713</a>
for eligibility requirements. for eligibility requirements.
For the 2021 nomcom, see also <a href="{% url 'ietf.doc.views_doc.document_main' name='rfc8989' %}">RFC 8989</a>.
</p> </p>
</div> </div>
@ -181,7 +180,7 @@
dagger symbol (<strong>&dagger;</strong>) next to it, or listed on your dagger symbol (<strong>&dagger;</strong>) next to it, or listed on your
<a href="{% url 'ietf.community.views.view_list' user.username %}">notification subscription page</a>. Most of this <a href="{% url 'ietf.community.views.view_list' user.username %}">notification subscription page</a>. Most of this
information can be edited or removed on these pages. There are some exceptions, such information can be edited or removed on these pages. There are some exceptions, such
as photos, which currently require an email to <a href="mailto:{{settings.SECRETARIAT_INFO_EMAIL}}">the Secretariat</a> as photos, which currently require an email to <a href="mailto:{{settings.SECRETARIAT_SUPPORT_EMAIL}}">the Secretariat</a>
if you wish to update or remove the information. if you wish to update or remove the information.
</p> </p>