Skip to content

Commit 7e83064

Browse files
committed
Add nominee merge view.
See ietf-tools#930 - Legacy-Id: 5183
1 parent 34a72e0 commit 7e83064

5 files changed

Lines changed: 153 additions & 13 deletions

File tree

ietf/nomcom/forms.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ def parse_params(self, *args, **kwargs):
8282
self.form.base_fields['members'].initial = ',\r\n'.join([role.email.address for role in members])
8383

8484
def process_preview(self, request, form, context):
85-
members_email = form.cleaned_data['members'].replace('\r\n', '').replace(' ', '').split(',')
85+
emails = form.cleaned_data['members'].replace('\r\n', '')
86+
members_email = map(unicode.strip, emails.split(','))
8687

8788
members_info = []
8889
emails_not_found = []
@@ -184,6 +185,50 @@ def __init__(self, *args, **kwargs):
184185
self.fields['public_key'].required = True
185186

186187

188+
class MergeForm(BaseNomcomForm, forms.Form):
189+
190+
secondary_emails = custom_fields.MultiEmailField(label="Secondary email address (remove this):")
191+
primary_email = forms.EmailField(label="Primary email address",
192+
widget=forms.TextInput(attrs={'size': '40'}))
193+
194+
fieldsets = [('Emails', ('primary_email', 'secondary_emails'))]
195+
196+
def __init__(self, *args, **kwargs):
197+
self.nomcom = kwargs.pop('nomcom', None)
198+
super(MergeForm, self).__init__(*args, **kwargs)
199+
200+
def clean(self):
201+
primary_email = self.cleaned_data.get("primary_email")
202+
secondary_emails = self.cleaned_data.get("secondary_emails")
203+
if primary_email and secondary_emails:
204+
if primary_email in secondary_emails:
205+
msg = "Primary and secondary email address must be differents"
206+
self._errors["primary_email"] = self.error_class([msg])
207+
return self.cleaned_data
208+
209+
def save(self):
210+
primary_email = self.cleaned_data.get("primary_email")
211+
secondary_emails = self.cleaned_data.get("secondary_emails").replace('\r\n', '')
212+
secondary_emails = map(unicode.strip, secondary_emails.split(','))
213+
214+
primary_nominee = Nominee.objects.get(email__address=primary_email)
215+
secondary_nominees = Nominee.objects.filter(email__address__in=secondary_emails)
216+
for nominee in secondary_nominees:
217+
# move nominations
218+
nominee.nomination_set.all().update(nominee=primary_nominee)
219+
# move feedback
220+
nominee.feedback_set.all().update(nominee=primary_nominee)
221+
# move nomineepositions
222+
for nominee_position in nominee.nomineeposition_set.all():
223+
if not NomineePosition.objects.filter(position=nominee_position.position,
224+
nominee=primary_nominee):
225+
226+
nominee_position.nominee = primary_nominee
227+
nominee_position.save()
228+
229+
secondary_nominees.delete()
230+
231+
187232
class NominateForm(BaseNomcomForm, forms.ModelForm):
188233
comments = forms.CharField(label='Comments', widget=forms.Textarea())
189234

ietf/nomcom/tests.py

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,59 @@ def test_private_index_view(self):
7777

7878
def test_private_merge_view(self):
7979
"""Verify private merge view"""
80-
# TODO: complete merge nominations
80+
81+
# do nominations
82+
login_testing_unauthorized(self, COMMUNITY_USER, self.public_nominate_url)
83+
self.nominate_view(public=True, nominee_email=u'nominee@example.com',
84+
position='IAOC')
85+
self.nominate_view(public=True, nominee_email=u'nominee2@example.com',
86+
position='IAOC')
87+
self.nominate_view(public=True, nominee_email=u'nominee3@example.com',
88+
position='IAB')
89+
self.nominate_view(public=True, nominee_email=u'nominee4@example.com',
90+
position='TSV')
91+
92+
self.client.logout()
93+
94+
# merge nominations
8195
self.access_chair_url(self.private_merge_url)
96+
97+
test_data = {"secondary_emails": "nominee@example.com, nominee2@example.com",
98+
"primary_email": "nominee@example.com"}
99+
response = self.client.post(self.private_merge_url, test_data)
100+
self.assertEqual(response.status_code, 200)
101+
self.assertContains(response, "info-message-error")
102+
103+
test_data = {"primary_email": "nominee@example.com",
104+
"secondary_emails": ""}
105+
response = self.client.post(self.private_merge_url, test_data)
106+
self.assertEqual(response.status_code, 200)
107+
self.assertContains(response, "info-message-error")
108+
109+
test_data = {"primary_email": "",
110+
"secondary_emails": "nominee@example.com"}
111+
response = self.client.post(self.private_merge_url, test_data)
112+
self.assertEqual(response.status_code, 200)
113+
self.assertContains(response, "info-message-error")
114+
115+
test_data = {"secondary_emails": """nominee2@example.com,
116+
nominee3@example.com,
117+
nominee4@example.com""",
118+
"primary_email": "nominee@example.com"}
119+
120+
response = self.client.post(self.private_merge_url, test_data)
121+
self.assertEqual(response.status_code, 200)
122+
self.assertContains(response, "info-message-success")
123+
124+
self.assertEqual(Nominee.objects.filter(email__address='nominee2@example.com').count(), 0)
125+
self.assertEqual(Nominee.objects.filter(email__address='nominee3@example.com').count(), 0)
126+
self.assertEqual(Nominee.objects.filter(email__address='nominee4@example.com').count(), 0)
127+
128+
nominee = Nominee.objects.get(email__address='nominee@example.com')
129+
self.assertEqual(Nomination.objects.filter(nominee=nominee).count(), 4)
130+
self.assertEqual(Feedback.objects.filter(nominee=nominee).count(), 4)
131+
self.assertEqual(NomineePosition.objects.filter(nominee=nominee).count(), 3)
132+
82133
self.client.logout()
83134

84135
def change_members(self, members):
@@ -188,13 +239,18 @@ def test_comments_view(self):
188239
def test_public_nominate(self):
189240
login_testing_unauthorized(self, COMMUNITY_USER, self.public_nominate_url)
190241
return self.nominate_view(public=True)
242+
self.client.logout()
191243

192244
def test_private_nominate(self):
193245
self.access_member_url(self.private_nominate_url)
194246
return self.nominate_view(public=False)
247+
self.client.logout()
248+
249+
def nominate_view(self, *args, **kwargs):
250+
public = kwargs.pop('public', True)
251+
nominee_email = kwargs.pop('nominee_email', u'nominee@example.com')
252+
position_name = kwargs.pop('position', 'IAOC')
195253

196-
def nominate_view(self, public=True):
197-
"""Verify nominate view"""
198254
if public:
199255
nominate_url = self.public_nominate_url
200256
else:
@@ -214,8 +270,8 @@ def nominate_view(self, public=True):
214270
self.assertEqual(response.status_code, 200)
215271
self.assertContains(response, "nominateform")
216272

217-
position = Position.objects.get(name='IAOC')
218-
candidate_email = u'nominee@example.com'
273+
position = Position.objects.get(name=position_name)
274+
candidate_email = nominee_email
219275
candidate_name = u'nominee'
220276
comments = 'test nominate view'
221277
candidate_phone = u'123456'
@@ -252,7 +308,6 @@ def nominate_view(self, public=True):
252308
nominee=nominee,
253309
comments=feedback,
254310
nominator_email="%s%s" % (COMMUNITY_USER, EMAIL_DOMAIN))
255-
self.client.logout()
256311

257312

258313
class NomineePositionStateSaveTest(TestCase):

ietf/nomcom/views.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from ietf.nomcom.utils import get_nomcom_by_year, HOME_TEMPLATE
1010
from ietf.nomcom.decorators import member_required
11-
from ietf.nomcom.forms import EditPublicKeyForm, NominateForm
11+
from ietf.nomcom.forms import EditPublicKeyForm, NominateForm, MergeForm
1212
from ietf.nomcom.models import Position
1313

1414

@@ -34,11 +34,21 @@ def private_index(request, year):
3434

3535
@member_required(role='chair')
3636
def private_merge(request, year):
37-
# TODO: complete merge nominations
3837
nomcom = get_nomcom_by_year(year)
38+
message = None
39+
if request.method == 'POST':
40+
form = MergeForm(request.POST, nomcom=nomcom)
41+
if form.is_valid():
42+
form.save()
43+
message = ('success', 'The emails has been unified')
44+
else:
45+
form = MergeForm(nomcom=nomcom)
46+
3947
return render_to_response('nomcom/private_merge.html',
4048
{'nomcom': nomcom,
4149
'year': year,
50+
'form': form,
51+
'message': message,
4252
'selected': 'merge'}, RequestContext(request))
4353

4454

ietf/templates/nomcom/private_merge.html

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,35 @@
55
{% block nomcom_content %}
66

77
<h2>Merging nominee email addresses</h2>
8-
<p>If a nominee has been nominated with multiple email addresses, the nominee will appear multiple times in the nomination list, as the email address is used as the unique identifier for each nominee. In order to permit comments and nominations to be submitted under multiple email addresses, there is a list of secondary email addresses which needs to be kept up-to-date. When nominations of one particular nominee have already been made under different email addresses, the nomination comments from the secondary address also needs to be merged with those under the primary address. It doesn't matter particularly which email address is used as primary, as far as the nominee information maintenance goes, but it's probably handier for the nomcom if the primary address is the one which the nominee prefers at the time.</p>
8+
<p>
9+
If a nominee has been nominated with multiple email addresses, the nominee will
10+
appear multiple times in the nomination list, as the email address is used as
11+
the unique identifier for each nominee. In order to permit comments and nominations
12+
to be submitted under multiple email addresses, there is a list of secondary email
13+
addresses which needs to be kept up-to-date. When nominations of one particular nominee
14+
have already been made under different email addresses, the nomination comments from the
15+
secondary address also needs to be merged with those under the primary address.
16+
</p>
17+
<p>
18+
It doesn't matter particularly which email address is used as primary, as far as the
19+
nominee information maintenance goes, but it's probably handier for the nomcom if the
20+
primary address is the one which the nominee prefers at the time.
21+
</p>
22+
23+
24+
{% if message %}
25+
<div class="info-message-{{ message.0 }}">{{ message.1 }}</div>
26+
{% endif %}
27+
28+
{% if form.errors %}<div class="info-message-error">Please correct the following errors</div>{% endif %}
29+
30+
<form id="nominateform" action="" method="post">{% csrf_token %}
31+
{{ form }}
32+
33+
<div class="submitrow">
34+
<input type="submit" value="Save" name="save" />
35+
</div>
36+
37+
</form>
38+
939
{% endblock %}

ietf/templates/nomcom/private_nominate.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
<form id="nominateform" action="" method="post">{% csrf_token %}
3131
{{ form }}
3232

33-
<div class="submitrow">
34-
<input type="submit" value="Save" name="save" />
35-
</div>
33+
<div class="submitrow">
34+
<input type="submit" value="Save" name="save" />
35+
</div>
3636

3737
</form>
3838
{% endif %}

0 commit comments

Comments
 (0)