Skip to content

Commit dc5ae39

Browse files
committed
Improved SearchablePersonField to show the primary email address for any search results where a name appears more than once.
Simplified the edit nominee form. Replaced the merge nominee form with a request to the secretariat to merge Person records. Fixes ietf-tools#1847. Added merging nominees to the secretariat's person merging script. Restructured the person merging script to make it testable. Updated some tests to match changes to the mailtriggers that hadn't made it to the fixtures. - Legacy-Id: 10625
1 parent aadcf2d commit dc5ae39

15 files changed

Lines changed: 331 additions & 420 deletions

File tree

ietf/bin/merge-person-records

Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ import django
1212
django.setup()
1313

1414
import argparse
15-
import pprint
16-
from django.contrib import admin
17-
from django.contrib.auth.models import User
1815
from ietf.person.models import Person
1916

17+
from ietf.person.utils import merge_persons
18+
2019
parser = argparse.ArgumentParser()
2120
parser.add_argument("source_id",type=int)
2221
parser.add_argument("target_id",type=int)
@@ -30,62 +29,4 @@ response = raw_input('Ok to continue y/n? ')
3029
if response.lower() != 'y':
3130
sys.exit()
3231

33-
# merge emails
34-
for email in source.email_set.all():
35-
print "Merging email: {}".format(email.address)
36-
email.person = target
37-
email.save()
38-
39-
# merge aliases
40-
target_aliases = [ a.name for a in target.alias_set.all() ]
41-
for alias in source.alias_set.all():
42-
if alias.name in target_aliases:
43-
alias.delete()
44-
else:
45-
print "Merging alias: {}".format(alias.name)
46-
alias.person = target
47-
alias.save()
48-
49-
# merge DocEvents
50-
for docevent in source.docevent_set.all():
51-
docevent.by = target
52-
docevent.save()
53-
54-
# merge SubmissionEvents
55-
for subevent in source.submissionevent_set.all():
56-
subevent.by = target
57-
subevent.save()
58-
59-
# merge Messages
60-
for message in source.message_set.all():
61-
message.by = target
62-
message.save()
63-
64-
# merge Constraints
65-
for constraint in source.constraint_set.all():
66-
constraint.person = target
67-
constraint.save()
68-
69-
# merge Roles
70-
for role in source.role_set.all():
71-
role.person = target
72-
role.save()
73-
74-
# check for any remaining relationships and delete if none
75-
objs = [source]
76-
opts = Person._meta
77-
user = User.objects.filter(is_superuser=True).first()
78-
admin_site = admin.site
79-
using = 'default'
80-
81-
deletable_objects, perms_needed, protected = admin.utils.get_deleted_objects(
82-
objs, opts, user, admin_site, using)
83-
84-
if len(deletable_objects) > 1:
85-
print "Not Deleting Person: {}({})".format(source.ascii,source.pk)
86-
print "Related objects remain:"
87-
pprint.pprint(deletable_objects[1])
88-
89-
else:
90-
print "Deleting Person: {}({})".format(source.ascii,source.pk)
91-
source.delete()
32+
merge_persons(source,target,sys.stdout)

ietf/doc/tests_draft.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,6 +1268,7 @@ def setUp(self):
12681268
expires=datetime.datetime.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
12691269
group=mars_wg,
12701270
)
1271+
self.basea.documentauthor_set.create(author=Email.objects.create(address="basea_author@example.com"),order=1)
12711272

12721273
self.baseb = Document.objects.create(
12731274
name="draft-test-base-b",
@@ -1278,6 +1279,7 @@ def setUp(self):
12781279
expires=datetime.datetime.now() - datetime.timedelta(days = 365 - settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
12791280
group=mars_wg,
12801281
)
1282+
self.baseb.documentauthor_set.create(author=Email.objects.create(address="baseb_author@example.com"),order=1)
12811283

12821284
self.replacea = Document.objects.create(
12831285
name="draft-test-replace-a",
@@ -1288,6 +1290,7 @@ def setUp(self):
12881290
expires=datetime.datetime.now() + datetime.timedelta(days = settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
12891291
group=mars_wg,
12901292
)
1293+
self.replacea.documentauthor_set.create(author=Email.objects.create(address="replacea_author@example.com"),order=1)
12911294

12921295
self.replaceboth = Document.objects.create(
12931296
name="draft-test-replace-both",
@@ -1298,6 +1301,7 @@ def setUp(self):
12981301
expires=datetime.datetime.now() + datetime.timedelta(days = settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
12991302
group=mars_wg,
13001303
)
1304+
self.replaceboth.documentauthor_set.create(author=Email.objects.create(address="replaceboth_author@example.com"),order=1)
13011305

13021306
self.basea.set_state(State.objects.get(used=True, type="draft", slug="active"))
13031307
self.baseb.set_state(State.objects.get(used=True, type="draft", slug="expired"))
@@ -1332,8 +1336,8 @@ def test_change_replaces(self):
13321336
self.assertTrue(not RelatedDocument.objects.filter(relationship='possibly-replaces', source=self.replacea))
13331337
self.assertEqual(len(outbox), 1)
13341338
self.assertTrue('replacement status updated' in outbox[-1]['Subject'])
1335-
self.assertTrue('base-a@' in outbox[-1]['To'])
1336-
self.assertTrue('replace-a@' in outbox[-1]['To'])
1339+
self.assertTrue('replacea_author@' in outbox[-1]['To'])
1340+
self.assertTrue('basea_author@' in outbox[-1]['To'])
13371341

13381342
empty_outbox()
13391343
# Post that says replaceboth replaces both base a and base b
@@ -1344,9 +1348,9 @@ def test_change_replaces(self):
13441348
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl')
13451349
self.assertEqual(Document.objects.get(name='draft-test-base-b').get_state().slug,'repl')
13461350
self.assertEqual(len(outbox), 1)
1347-
self.assertTrue('base-a@' in outbox[-1]['To'])
1348-
self.assertTrue('base-b@' in outbox[-1]['To'])
1349-
self.assertTrue('replace-both@' in outbox[-1]['To'])
1351+
self.assertTrue('basea_author@' in outbox[-1]['To'])
1352+
self.assertTrue('baseb_author@' in outbox[-1]['To'])
1353+
self.assertTrue('replaceboth_author@' in outbox[-1]['To'])
13501354

13511355
# Post that undoes replaceboth
13521356
empty_outbox()
@@ -1355,18 +1359,18 @@ def test_change_replaces(self):
13551359
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl') # Because A is still also replaced by replacea
13561360
self.assertEqual(Document.objects.get(name='draft-test-base-b').get_state().slug,'expired')
13571361
self.assertEqual(len(outbox), 1)
1358-
self.assertTrue('base-a@' in outbox[-1]['To'])
1359-
self.assertTrue('base-b@' in outbox[-1]['To'])
1360-
self.assertTrue('replace-both@' in outbox[-1]['To'])
1362+
self.assertTrue('basea_author@' in outbox[-1]['To'])
1363+
self.assertTrue('baseb_author@' in outbox[-1]['To'])
1364+
self.assertTrue('replaceboth_author@' in outbox[-1]['To'])
13611365

13621366
# Post that undoes replacea
13631367
empty_outbox()
13641368
url = urlreverse('doc_change_replaces', kwargs=dict(name=self.replacea.name))
13651369
r = self.client.post(url, dict(replaces=""))
13661370
self.assertEqual(r.status_code, 302)
13671371
self.assertEqual(Document.objects.get(name='draft-test-base-a').get_state().slug,'active')
1368-
self.assertTrue('base-a@' in outbox[-1]['To'])
1369-
self.assertTrue('replace-a@' in outbox[-1]['To'])
1372+
self.assertTrue('basea_author@' in outbox[-1]['To'])
1373+
self.assertTrue('replacea_author@' in outbox[-1]['To'])
13701374

13711375

13721376
def test_review_possibly_replaces(self):

ietf/doc/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from ietf.utils.mail import send_mail
2121
from ietf.mailtrigger.utils import gather_address_lists
2222

23+
import debug # pyflakes:ignore
24+
2325
#TODO FIXME - it would be better if this lived in ietf/doc/mails.py, but there's
2426
# an import order issue to work out.
2527
def email_update_telechat(request, doc, text):
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import unicode_literals
3+
4+
from django.db import migrations
5+
6+
def forward(apps, schema_editor):
7+
8+
Recipient=apps.get_model('mailtrigger','Recipient')
9+
MailTrigger=apps.get_model('mailtrigger','MailTrigger')
10+
11+
m = MailTrigger.objects.create(
12+
slug='person_merge_requested',
13+
desc="Recipients for a message requesting that duplicated Person records be merged ")
14+
m.to = Recipient.objects.filter(slug__in=['ietf_secretariat', ])
15+
16+
def reverse(apps, schema_editor):
17+
MailTrigger=apps.get_model('mailtrigger','MailTrigger')
18+
MailTrigger.objects.filter(slug='person_merge_requested').delete()
19+
20+
class Migration(migrations.Migration):
21+
22+
dependencies = [
23+
('mailtrigger', '0002_auto_20150809_1314'),
24+
]
25+
26+
operations = [
27+
migrations.RunPython(forward, reverse)
28+
]

ietf/name/fixtures/names.json

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@
648648
{
649649
"fields": {
650650
"order": 0,
651+
"prefix": "charter",
651652
"used": true,
652653
"name": "Charter",
653654
"desc": ""
@@ -658,6 +659,7 @@
658659
{
659660
"fields": {
660661
"order": 0,
662+
"prefix": "agenda",
661663
"used": true,
662664
"name": "Agenda",
663665
"desc": ""
@@ -668,6 +670,7 @@
668670
{
669671
"fields": {
670672
"order": 0,
673+
"prefix": "minutes",
671674
"used": true,
672675
"name": "Minutes",
673676
"desc": ""
@@ -678,6 +681,7 @@
678681
{
679682
"fields": {
680683
"order": 0,
684+
"prefix": "slides",
681685
"used": true,
682686
"name": "Slides",
683687
"desc": ""
@@ -688,6 +692,7 @@
688692
{
689693
"fields": {
690694
"order": 0,
695+
"prefix": "draft",
691696
"used": true,
692697
"name": "Draft",
693698
"desc": ""
@@ -698,6 +703,7 @@
698703
{
699704
"fields": {
700705
"order": 0,
706+
"prefix": "liai-att",
701707
"used": true,
702708
"name": "Liaison Attachment",
703709
"desc": ""
@@ -708,6 +714,7 @@
708714
{
709715
"fields": {
710716
"order": 0,
717+
"prefix": "conflict-review",
711718
"used": true,
712719
"name": "Conflict Review",
713720
"desc": ""
@@ -718,6 +725,7 @@
718725
{
719726
"fields": {
720727
"order": 0,
728+
"prefix": "status-change",
721729
"used": true,
722730
"name": "Status Change",
723731
"desc": ""
@@ -728,6 +736,7 @@
728736
{
729737
"fields": {
730738
"order": 0,
739+
"prefix": "",
731740
"used": false,
732741
"name": "Shepherd's writeup",
733742
"desc": ""
@@ -738,6 +747,7 @@
738747
{
739748
"fields": {
740749
"order": 0,
750+
"prefix": "",
741751
"used": false,
742752
"name": "Liaison",
743753
"desc": ""
@@ -748,6 +758,7 @@
748758
{
749759
"fields": {
750760
"order": 0,
761+
"prefix": "recording",
751762
"used": true,
752763
"name": "Recording",
753764
"desc": ""
@@ -758,6 +769,7 @@
758769
{
759770
"fields": {
760771
"order": 0,
772+
"prefix": "bluesheets",
761773
"used": true,
762774
"name": "Bluesheets",
763775
"desc": ""
@@ -1580,6 +1592,16 @@
15801592
"model": "name.liaisonstatementeventtypename",
15811593
"pk": "comment"
15821594
},
1595+
{
1596+
"fields": {
1597+
"order": 10,
1598+
"used": true,
1599+
"name": "Private Comment",
1600+
"desc": ""
1601+
},
1602+
"model": "name.liaisonstatementeventtypename",
1603+
"pk": "private_comment"
1604+
},
15831605
{
15841606
"fields": {
15851607
"order": 1,
@@ -4541,6 +4563,14 @@
45414563
"model": "mailtrigger.recipient",
45424564
"pk": "doc_authors"
45434565
},
4566+
{
4567+
"fields": {
4568+
"template": "{{doc.author_list}}",
4569+
"desc": "The authors of the document, without using the draft aliases"
4570+
},
4571+
"model": "mailtrigger.recipient",
4572+
"pk": "doc_authors_expanded"
4573+
},
45444574
{
45454575
"fields": {
45464576
"template": null,
@@ -4701,6 +4731,14 @@
47014731
"model": "mailtrigger.recipient",
47024732
"pk": "iana_last_call"
47034733
},
4734+
{
4735+
"fields": {
4736+
"template": "<i-d-announce@ietf.org>",
4737+
"desc": "The I-D-Announce Email List"
4738+
},
4739+
"model": "mailtrigger.recipient",
4740+
"pk": "id_announce"
4741+
},
47044742
{
47054743
"fields": {
47064744
"template": "The IESG <iesg@ietf.org>",
@@ -5306,11 +5344,7 @@
53065344
"fields": {
53075345
"cc": [],
53085346
"to": [
5309-
"doc_authors",
5310-
"doc_group_chairs",
5311-
"doc_group_responsible_directors",
5312-
"doc_notify",
5313-
"doc_shepherd"
5347+
"doc_authors_expanded"
53145348
],
53155349
"desc": "Recipients when what a document replaces or is replaced by changes"
53165350
},
@@ -5698,6 +5732,17 @@
56985732
"model": "mailtrigger.mailtrigger",
56995733
"pk": "nomination_received"
57005734
},
5735+
{
5736+
"fields": {
5737+
"cc": [],
5738+
"to": [
5739+
"ietf_secretariat"
5740+
],
5741+
"desc": "Recipients for a message requesting that duplicated Person records be merged "
5742+
},
5743+
"model": "mailtrigger.mailtrigger",
5744+
"pk": "person_merge_requested"
5745+
},
57015746
{
57025747
"fields": {
57035748
"cc": [
@@ -5843,7 +5888,7 @@
58435888
"submission_group_mail_list"
58445889
],
58455890
"to": [
5846-
"ietf_announce"
5891+
"id_announce"
58475892
],
58485893
"desc": "Recipients for the announcement of a successfully submitted draft"
58495894
},

0 commit comments

Comments
 (0)