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:
parent
fa53de03e3
commit
aadcf2d056
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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 %}
|
||||
|
|
Loading…
Reference in a new issue