Skip to content

Commit 26fcce9

Browse files
committed
Brought back the nomcom nominee merge functionality which was inadvertently removed in January. There is now both a Merge Nominee and a Merge Person form, with additional instructions which should make it easier to choose the right one for the task.
- Legacy-Id: 12017
2 parents 5089651 + efa3228 commit 26fcce9

8 files changed

Lines changed: 407 additions & 19 deletions

File tree

ietf/nomcom/admin.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ class NominationAdmin(admin.ModelAdmin):
1313

1414

1515
class NomineeAdmin(admin.ModelAdmin):
16-
list_display = ('email',)
17-
16+
list_display = ('email', 'person', 'duplicated', 'nomcom')
17+
search_fields = ('email__address', 'person__name', )
18+
list_filter = ('nomcom', )
1819

1920
class NomineePositionAdmin(admin.ModelAdmin):
2021
pass

ietf/nomcom/forms.py

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@
1111
from ietf.dbtemplate.forms import DBTemplateForm
1212
from ietf.group.models import Group, Role
1313
from ietf.ietfauth.utils import role_required
14-
from ietf.name.models import RoleName, FeedbackTypeName
14+
from ietf.name.models import RoleName, FeedbackTypeName, NomineePositionStateName
1515
from ietf.nomcom.models import ( NomCom, Nomination, Nominee, NomineePosition,
1616
Position, Feedback, ReminderDates )
1717
from ietf.nomcom.utils import (NOMINATION_RECEIPT_TEMPLATE, FEEDBACK_RECEIPT_TEMPLATE,
1818
get_user_email, validate_private_key, validate_public_key,
1919
make_nomineeposition, make_nomineeposition_for_newperson,
2020
create_feedback_email)
2121
from ietf.person.models import Email
22-
from ietf.person.fields import SearchableEmailField, SearchablePersonField, SearchablePersonsField
22+
from ietf.person.fields import (SearchableEmailField, SearchableEmailsField,
23+
SearchablePersonField, SearchablePersonsField )
2324
from ietf.utils.fields import MultiEmailField
2425
from ietf.utils.mail import send_mail
2526
from ietf.mailtrigger.utils import gather_address_lists
@@ -221,14 +222,95 @@ def clean_public_key(self):
221222
raise forms.ValidationError('Invalid public key. Error was: %s' % error)
222223

223224

224-
class MergeForm(forms.Form):
225+
class MergeNomineeForm(forms.Form):
226+
227+
primary_email = SearchableEmailField(
228+
help_text="Select the email of the Nominee record you want to use as the primary record.")
229+
secondary_emails = SearchableEmailsField(
230+
help_text="Select all the duplicates that should be consolidated with the primary "
231+
"Nominee record. Nominations already received with any of these email address "
232+
"will be moved to show under the primary address." )
233+
234+
def __init__(self, *args, **kwargs):
235+
self.nomcom = kwargs.pop('nomcom', None)
236+
super(MergeNomineeForm, self).__init__(*args, **kwargs)
237+
238+
def clean_primary_email(self):
239+
email = self.cleaned_data['primary_email']
240+
nominees = Nominee.objects.get_by_nomcom(self.nomcom).not_duplicated().filter(email__address=email)
241+
if not nominees:
242+
msg = "No nominee with this email exists"
243+
self._errors["primary_email"] = self.error_class([msg])
244+
245+
return email
246+
247+
def clean_secondary_emails(self):
248+
emails = self.cleaned_data['secondary_emails']
249+
for email in emails:
250+
nominees = Nominee.objects.get_by_nomcom(self.nomcom).not_duplicated().filter(email__address=email)
251+
if not nominees:
252+
msg = "No nominee with email %s exists" % email
253+
self._errors["primary_email"] = self.error_class([msg])
254+
break
255+
256+
return emails
257+
258+
def clean(self):
259+
primary_email = self.cleaned_data.get("primary_email")
260+
secondary_emails = self.cleaned_data.get("secondary_emails")
261+
if primary_email and secondary_emails:
262+
if primary_email in secondary_emails:
263+
msg = "Primary and secondary email address must be differents"
264+
self._errors["primary_email"] = self.error_class([msg])
265+
return self.cleaned_data
266+
267+
def save(self):
268+
primary_email = self.cleaned_data.get("primary_email")
269+
secondary_emails = self.cleaned_data.get("secondary_emails")
270+
271+
primary_nominee = Nominee.objects.get_by_nomcom(self.nomcom).get(email__address=primary_email)
272+
while primary_nominee.duplicated:
273+
primary_nominee = primary_nominee.duplicated
274+
secondary_nominees = Nominee.objects.get_by_nomcom(self.nomcom).filter(email__address__in=secondary_emails)
275+
for nominee in secondary_nominees:
276+
# move nominations
277+
nominee.nomination_set.all().update(nominee=primary_nominee)
278+
# move feedback
279+
for fb in nominee.feedback_set.all():
280+
fb.nominees.remove(nominee)
281+
fb.nominees.add(primary_nominee)
282+
# move nomineepositions
283+
for nominee_position in nominee.nomineeposition_set.all():
284+
primary_nominee_positions = NomineePosition.objects.filter(position=nominee_position.position,
285+
nominee=primary_nominee)
286+
primary_nominee_position = primary_nominee_positions and primary_nominee_positions[0] or None
287+
288+
if primary_nominee_position:
289+
# if already a nomineeposition object for a position and nominee,
290+
# update the nomineepostion of primary nominee with the state
291+
if nominee_position.state.slug == 'accepted' or primary_nominee_position.state.slug == 'accepted':
292+
primary_nominee_position.state = NomineePositionStateName.objects.get(slug='accepted')
293+
primary_nominee_position.save()
294+
if nominee_position.state.slug == 'declined' and primary_nominee_position.state.slug == 'pending':
295+
primary_nominee_position.state = NomineePositionStateName.objects.get(slug='declined')
296+
primary_nominee_position.save()
297+
else:
298+
# It is not allowed two or more nomineeposition objects with same position and nominee
299+
# move nominee_position object to primary nominee
300+
nominee_position.nominee = primary_nominee
301+
nominee_position.save()
302+
303+
nominee.duplicated = primary_nominee
304+
nominee.save()
305+
306+
class MergePersonForm(forms.Form):
225307

226308
primary_person = SearchablePersonField(help_text="Select the person you want the datatracker to keep")
227309
duplicate_persons = SearchablePersonsField(help_text="Select all the duplicates that should be merged into the primary person record")
228310

229311
def __init__(self, *args, **kwargs):
230312
self.nomcom = kwargs.pop('nomcom', None)
231-
super(MergeForm, self).__init__(*args, **kwargs)
313+
super(MergePersonForm, self).__init__(*args, **kwargs)
232314

233315
def clean(self):
234316
primary_person = self.cleaned_data.get("primary_person")
@@ -767,6 +849,20 @@ def __init__(self, *args, **kwargs):
767849
self.fields['nominee_email'].initial = self.instance.email
768850
self.fields['nominee_email'].help_text = "If the address you are looking for does not appear in this list, ask the nominee (or the secretariat) to add the address to their datatracker account and ensure it is marked as active."
769851

852+
def clean(self):
853+
nominee_email = self.cleaned_data.get("nominee_email")
854+
others = Nominee.objects.filter(email=nominee_email, nomcom=self.instance.nomcom)
855+
if others.exists():
856+
msg = ( "Changing email address for %s (#%s): There already exists a nominee "
857+
"with email address <%s>: %s -- please use the "
858+
"<a ref=\"{% url 'ietf.nomcom.views.private_merge_nominee' %}\">Merge Nominee</a> "
859+
"form instead." % (
860+
self.instance.name(),
861+
self.instance.pk, nominee_email,
862+
(", ".join( "%s (#%s)" %( n.name(), n.pk) for n in others))) )
863+
raise forms.ValidationError(mark_safe(msg))
864+
return self.cleaned_data
865+
770866
def save(self, commit=True):
771867
nominee = super(EditNomineeForm, self).save(commit=False)
772868
nominee_email = self.cleaned_data.get("nominee_email")

0 commit comments

Comments
 (0)