Added selecting existing people to the workflow for chair classification of nominations. Renamed some utility functions to be slightly more self-documenting.

- Legacy-Id: 10620
This commit is contained in:
Robert Sparks 2015-12-22 04:32:48 +00:00
parent fa53de03e3
commit aadcf2d056
4 changed files with 115 additions and 44 deletions

View file

@ -16,7 +16,7 @@ from ietf.nomcom.models import ( NomCom, Nomination, Nominee, NomineePosition,
Position, Feedback, ReminderDates )
from ietf.nomcom.utils import (NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEMPLATE,
get_user_email, validate_private_key, validate_public_key,
get_or_create_nominee, get_or_create_nominee_by_person,
make_nomineeposition, make_nomineeposition_for_newperson,
create_feedback_email)
from ietf.person.models import Email
from ietf.person.fields import SearchableEmailField
@ -24,6 +24,8 @@ from ietf.utils.fields import MultiEmailField
from ietf.utils.mail import send_mail
from ietf.mailtrigger.utils import gather_address_lists
import debug # pyflakes:ignore
ROLODEX_URL = getattr(settings, 'ROLODEX_URL', None)
@ -361,7 +363,7 @@ class NominateForm(forms.ModelForm):
if nominator_email:
emails = Email.objects.filter(address=nominator_email)
author = emails and emails[0] or None
nominee = get_or_create_nominee_by_person (self.nomcom, searched_email.person, position, author)
nominee = make_nomineeposition(self.nomcom, searched_email.person, position, author)
# Complete nomination data
feedback = Feedback.objects.create(nomcom=self.nomcom,
@ -471,7 +473,7 @@ class NominateNewPersonForm(forms.ModelForm):
author = emails and emails[0] or None
## This is where it should change - validation of the email field should fail if the email exists
## The function should become make_nominee_from_newperson)
nominee = get_or_create_nominee(self.nomcom, candidate_name, candidate_email, position, author)
nominee = make_nomineeposition_for_newperson(self.nomcom, candidate_name, candidate_email, position, author)
# Complete nomination data
feedback = Feedback.objects.create(nomcom=self.nomcom,
@ -734,13 +736,34 @@ class MutableFeedbackForm(forms.ModelForm):
help_text='Hold down "Control", or "Command" on a Mac, to select more than one.')
else:
self.fields['position'] = forms.ModelChoiceField(queryset=Position.objects.get_by_nomcom(self.nomcom).opened(), label="Position")
self.fields['candidate_name'] = forms.CharField(label="Candidate name")
self.fields['candidate_email'] = forms.EmailField(label="Candidate email")
self.fields['searched_email'] = SearchableEmailField(only_users=False,help_text="Try to find the candidate you are classifying with this field first. Only use the name and email fields below if this search does not find the candidate.",label="Candidate",required=False)
self.fields['candidate_name'] = forms.CharField(label="Candidate name",help_text="Only fill in this name field if the search doesn't find the person you are classifying",required=False)
self.fields['candidate_email'] = forms.EmailField(label="Candidate email",help_text="Only fill in this email field if the search doesn't find the person you are classifying",required=False)
self.fields['candidate_phone'] = forms.CharField(label="Candidate phone", required=False)
def clean(self):
cleaned_data = super(MutableFeedbackForm,self).clean()
if self.feedback_type.slug == 'nomina':
searched_email = self.cleaned_data.get('searched_email')
candidate_name = self.cleaned_data.get('candidate_name')
if candidate_name:
candidate_name = candidate_name.strip()
candidate_email = self.cleaned_data.get('candidate_email')
if candidate_email:
candidate_email = candidate_email.strip()
if not any([ searched_email and not candidate_name and not candidate_email,
not searched_email and candidate_name and candidate_email,
]):
raise forms.ValidationError("You must identify either an existing person (by searching with the candidate field) and leave the name and email fields blank, or leave the search field blank and provide both a name and email address.")
if candidate_email and Email.objects.filter(address=candidate_email).exists():
raise forms.ValidationError("%s already exists in the datatracker. Please search within the candidate field to find it and leave both the name and email fields blank." % candidate_email)
return cleaned_data
def save(self, commit=True):
feedback = super(MutableFeedbackForm, self).save(commit=False)
if self.instance.type.slug == 'nomina':
searched_email = self.cleaned_data['searched_email']
candidate_email = self.cleaned_data['candidate_email']
candidate_name = self.cleaned_data['candidate_name']
candidate_phone = self.cleaned_data['candidate_phone']
@ -752,7 +775,10 @@ class MutableFeedbackForm(forms.ModelForm):
emails = Email.objects.filter(address=nominator_email)
author = emails and emails[0] or None
nominee = get_or_create_nominee(self.nomcom, candidate_name, candidate_email, position, author)
if searched_email:
nominee = make_nomineeposition(self.nomcom, searched_email.person, position, author)
else:
nominee = make_nomineeposition_for_newperson(self.nomcom, candidate_name, candidate_email, position, author)
feedback.nominees.add(nominee)
feedback.positions.add(position)
Nomination.objects.create(

View file

@ -28,7 +28,7 @@ from ietf.nomcom.models import NomineePosition, Position, Nominee, \
NomineePositionStateName, Feedback, FeedbackTypeName, \
Nomination, FeedbackLastSeen
from ietf.nomcom.forms import EditMembersForm, EditMembersFormPreview
from ietf.nomcom.utils import get_nomcom_by_year, get_or_create_nominee, get_hash_nominee_position
from ietf.nomcom.utils import get_nomcom_by_year, make_nomineeposition, get_hash_nominee_position
from ietf.nomcom.management.commands.send_reminders import Command, is_time_to_send
from ietf.nomcom.factories import NomComFactory, FeedbackFactory, \
@ -951,20 +951,22 @@ class ReminderTest(TestCase):
today = datetime.date.today()
t_minus_3 = today - datetime.timedelta(days=3)
t_minus_4 = today - datetime.timedelta(days=4)
n = get_or_create_nominee(self.nomcom,"Nominee 1","nominee1@example.org",gen,None)
e1 = EmailFactory(address="nominee1@example.org",person=PersonFactory(name=u"Nominee 1"))
e2 = EmailFactory(address="nominee2@example.org",person=PersonFactory(name=u"Nominee 2"))
n = make_nomineeposition(self.nomcom,e1.person,gen,None)
np = n.nomineeposition_set.get(position=gen)
np.time = t_minus_3
np.save()
n = get_or_create_nominee(self.nomcom,"Nominee 1","nominee1@example.org",iab,None)
n = make_nomineeposition(self.nomcom,e1.person,iab,None)
np = n.nomineeposition_set.get(position=iab)
np.state = NomineePositionStateName.objects.get(slug='accepted')
np.time = t_minus_3
np.save()
n = get_or_create_nominee(self.nomcom,"Nominee 2","nominee2@example.org",rai,None)
n = make_nomineeposition(self.nomcom,e2.person,rai,None)
np = n.nomineeposition_set.get(position=rai)
np.time = t_minus_4
np.save()
n = get_or_create_nominee(self.nomcom,"Nominee 2","nominee2@example.org",gen,None)
n = make_nomineeposition(self.nomcom,e2.person,gen,None)
np = n.nomineeposition_set.get(position=gen)
np.state = NomineePositionStateName.objects.get(slug='accepted')
np.time = t_minus_4
@ -1445,14 +1447,51 @@ Junk body for testing
'form-0-id': fb.id,
'form-0-type': 'nomina',
'form-0-position': position.id,
'form-0-candidate_name' : nominee.name(),
'form-0-candidate_email' : nominee.email.address,
'form-0-searched_email' : nominee.email.address,
})
self.assertEqual(response.status_code,302)
fb = Feedback.objects.get(id=fb.id)
self.assertEqual(fb.type_id,'nomina')
self.assertEqual(nominee.feedback_set.count(),fb_count_before+1)
# Classify a newperson
fb = FeedbackFactory(nomcom=self.nc,type_id=None)
position = self.nc.position_set.first()
response = self.client.post(url, {'form-TOTAL_FORMS':1,
'form-INITIAL_FORMS':1,
'end':'Save feedback',
'form-0-id': fb.id,
'form-0-type': 'nomina',
'form-0-position': position.id,
'form-0-candidate_email' : 'newperson@example.com',
'form-0-candidate_name' : 'New Person',
})
self.assertEqual(response.status_code,302)
fb = Feedback.objects.get(id=fb.id)
self.assertEqual(fb.type_id,'nomina')
self.assertTrue(fb.nominees.filter(person__name='New Person').exists())
# check for failure when trying to add a newperson that already exists
fb = FeedbackFactory(nomcom=self.nc,type_id=None)
position = self.nc.position_set.all()[1]
nominee = self.nc.nominee_set.get(person__email__address='newperson@example.com')
fb_count_before = nominee.feedback_set.count()
response = self.client.post(url, {'form-TOTAL_FORMS':1,
'form-INITIAL_FORMS':1,
'end':'Save feedback',
'form-0-id': fb.id,
'form-0-type': 'nomina',
'form-0-position': position.id,
'form-0-candidate_email' : 'newperson@example.com',
'form-0-candidate_name' : 'New Person',
})
self.assertEqual(response.status_code,200)
self.assertTrue('already exists' in unicontent(response))
fb = Feedback.objects.get(id=fb.id)
self.assertEqual(fb.type_id,None)
self.assertEqual(nominee.feedback_set.count(),fb_count_before)
fb = FeedbackFactory(nomcom=self.nc,type_id=None)
np = NomineePosition.objects.filter(position__nomcom = self.nc,state='accepted').first()
fb_count_before = np.nominee.feedback_set.count()
@ -1461,7 +1500,7 @@ Junk body for testing
'end':'Save feedback',
'form-0-id': fb.id,
'form-0-type': 'questio',
'form-0-nominee': '%s_%s'%(np.position.id,np.nominee.id),
'form-0-nominee' : '%s_%s'%(np.position.id,np.nominee.id),
})
self.assertEqual(response.status_code,302)
fb = Feedback.objects.get(id=fb.id)
@ -1504,23 +1543,23 @@ Junk body for testing
self.assertEqual(q('input[name=\"form-0-type\"]').attr['value'],'nomina')
self.assertEqual(q('input[name=\"extra_ids\"]').attr['value'],'%s:comment' % fb2.id)
# Second formset
# Second formset
response = self.client.post(url, {'form-TOTAL_FORMS':1,
'form-INITIAL_FORMS':1,
'end':'Save feedback',
'form-0-id': fb1.id,
'form-0-type': 'nomina',
'form-0-position': new_position_for_nominee.id,
'form-0-candidate_name' : nominee.name(),
'form-0-candidate_email' : nominee.email.address,
'form-0-candidate_name' : 'Totally New Person',
'form-0-candidate_email': 'totallynew@example.org',
'extra_ids': '%s:comment' % fb2.id,
})
self.assertEqual(response.status_code,200) # Notice that this is also is not a 302
fb1 = Feedback.objects.get(id=fb1.id)
self.assertEqual(fb1.type_id,'nomina')
q = PyQuery(response.content)
self.assertEqual(q('input[name=\"form-0-type\"]').attr['value'],'comment')
self.assertFalse(q('input[name=\"extra_ids\"]'))
fb1 = Feedback.objects.get(id=fb1.id)
self.assertEqual(fb1.type_id,'nomina')
# Exercising the resulting third formset is identical to the simple test above
# that categorizes a single thing as a comment. Note that it returns a 302.

View file

@ -271,7 +271,7 @@ def send_reminder_to_nominees(nominees,type):
return addrs
def get_or_create_nominee_by_person(nomcom, candidate, position, author):
def make_nomineeposition(nomcom, candidate, position, author):
from ietf.nomcom.models import Nominee, NomineePosition
nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym
@ -349,33 +349,28 @@ def get_or_create_nominee_by_person(nomcom, candidate, position, author):
return nominee
def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, author):
def make_nomineeposition_for_newperson(nomcom, candidate_name, candidate_email, position, author):
## TODO: Assert here that there is no matching email or person, and change the code
## to not possibly stomp on existing things
# This is expected to fail if called with an existing email address
email = Email.objects.create(address=candidate_email)
person = Person.objects.create(name=candidate_name,
ascii=unaccent.asciify(candidate_name),
address=candidate_email)
email.person = person
email.save()
# Create person and email if candidate email does't exist and send email
email, created_email = Email.objects.get_or_create(address=candidate_email)
if created_email:
person = Person.objects.create(name=candidate_name,
ascii=unaccent.asciify(candidate_name),
address=candidate_email)
email.person = person
email.save()
# send email to secretariat and nomcomchair to warn about the new person
subject = 'New person is created'
from_email = settings.NOMCOM_FROM_EMAIL
(to_email, cc) = gather_address_lists('nomination_created_person',nomcom=nomcom)
context = {'email': email.address,
'fullname': email.person.name,
'person_id': email.person.id}
nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym
path = nomcom_template_path + INEXISTENT_PERSON_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
return get_or_create_nominee_by_person(nomcom, email.person, position, author)
# send email to secretariat and nomcomchair to warn about the new person
subject = 'New person is created'
from_email = settings.NOMCOM_FROM_EMAIL
(to_email, cc) = gather_address_lists('nomination_created_person',nomcom=nomcom)
context = {'email': email.address,
'fullname': email.person.name,
'person_id': email.person.id}
nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym
path = nomcom_template_path + INEXISTENT_PERSON_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
return make_nomineeposition(nomcom, email.person, position, author)
def getheader(header_text, default="ascii"):
"""Decode the specified header"""

View file

@ -3,8 +3,14 @@
{% load origin %}
{% load bootstrap3 %}
{% load staticfiles %}
{% load nomcom_tags %}
{% block pagehead %}
<link rel="stylesheet" href="{% static 'select2/select2.css' %}">
<link rel="stylesheet" href="{% static 'select2-bootstrap-css/select2-bootstrap.min.css' %}">
{% endblock %}
{% block subtitle %} - Feeback pending{% endblock %}
{% block morecss %}
@ -155,3 +161,8 @@
{% endif %}
{% endblock %}
{% block js %}
<script src="{% static 'select2/select2.min.js' %}"></script>
<script src="{% static 'ietf/js/select2-field.js' %}"></script>
{% endblock %}