Skip to content

Commit 839d0f8

Browse files
committed
checkpoint
- Legacy-Id: 10016
1 parent 1e84077 commit 839d0f8

18 files changed

Lines changed: 761 additions & 98 deletions

File tree

ietf/doc/mails.py

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
from ietf.utils.mail import send_mail, send_mail_text
1111
from ietf.ipr.utils import iprs_from_docs, related_docs
12-
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias, ConsensusDocEvent, DocTagName
12+
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias, ConsensusDocEvent
1313
from ietf.doc.utils import needed_ballot_positions
1414
from ietf.person.models import Person
1515
from ietf.group.models import Role
1616
from ietf.doc.models import Document
17-
from ietf.mailtoken.utils import gather_addresses
17+
from ietf.mailtoken.utils import gather_addresses, gather_address_list
1818

1919
def email_state_changed(request, doc, text):
2020
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
@@ -35,7 +35,7 @@ def email_stream_changed(request, doc, old_stream, new_stream, text=""):
3535
streams.append(old_stream.slug)
3636
if new_stream:
3737
streams.append(new_stream.slug)
38-
to = gather_addresses('doc_stream_changed',doc=doc,streams=streams)
38+
to = gather_address_list('doc_stream_changed',doc=doc,streams=streams)
3939

4040
if not to:
4141
return
@@ -74,6 +74,7 @@ def email_authors(request, doc, subject, text):
7474
def html_to_text(html):
7575
return strip_tags(html.replace("&lt;", "<").replace("&gt;", ">").replace("&amp;", "&").replace("<br>", "\n"))
7676

77+
#TODO Expunge this
7778
def email_ad(request, doc, ad, changed_by, text, subject=None):
7879
if not ad or not changed_by or ad == changed_by:
7980
return
@@ -406,7 +407,7 @@ def email_last_call_expired(doc):
406407
text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.get_state("draft-iesg").name
407408

408409
send_mail(None,
409-
gather_addresses('last_call_expired',doc=doc)
410+
gather_addresses('last_call_expired',doc=doc),
410411
"DraftTracker Mail System <iesg-secretary@ietf.org>",
411412
"Last Call Expired: %s" % doc.file_tag(),
412413
"doc/mail/change_notice.txt",
@@ -416,27 +417,8 @@ def email_last_call_expired(doc):
416417
cc = gather_addresses('last_call_expired_cc',doc=doc)
417418
)
418419

419-
def stream_state_email_recipients(doc, extra_recipients=[]):
420-
persons = set()
421-
res = []
422-
for r in Role.objects.filter(group=doc.group, name__in=("chair", "delegate")).select_related("person", "email"):
423-
res.append(r.formatted_email())
424-
persons.add(r.person)
425-
426-
for email in doc.authors.all():
427-
if email.person not in persons:
428-
res.append(email.formatted_email())
429-
persons.add(email.person)
430-
431-
for e in extra_recipients:
432-
if e.person not in persons:
433-
res.append(e.formatted_email())
434-
persons.add(e.person)
435-
436-
return res
437-
438420
def email_stream_state_changed(request, doc, prev_state, new_state, by, comment=""):
439-
recipients = stream_state_email_recipients(doc)
421+
recipients = gather_address_list('doc_stream_state_edited',doc=doc)
440422

441423
state_type = (prev_state or new_state).type
442424

@@ -452,12 +434,8 @@ def email_stream_state_changed(request, doc, prev_state, new_state, by, comment=
452434
comment=comment))
453435

454436
def email_stream_tags_changed(request, doc, added_tags, removed_tags, by, comment=""):
455-
extra_recipients = []
456-
457-
if DocTagName.objects.get(slug="sheph-u") in added_tags and doc.shepherd:
458-
extra_recipients.append(doc.shepherd)
459437

460-
recipients = stream_state_email_recipients(doc, extra_recipients)
438+
recipients = gather_address_list('doc_stream_state_edited',doc=doc)
461439

462440
send_mail(request, recipients, settings.DEFAULT_FROM_EMAIL,
463441
u"Tags changed for %s" % doc.name,

ietf/doc/tests_ballot.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ def test_request_last_call(self):
232232
send_last_call_request="1"))
233233
draft = Document.objects.get(name=draft.name)
234234
self.assertEqual(draft.get_state_slug("draft-iesg"), "lc-req")
235-
self.assertEqual(len(outbox), mailbox_before + 3)
235+
self.assertEqual(len(outbox), mailbox_before + 2)
236236
self.assertTrue("Last Call" in outbox[-1]['Subject'])
237237
self.assertTrue(draft.name in outbox[-1]['Subject'])
238238

@@ -387,7 +387,7 @@ def test_approve_ballot(self):
387387

388388
draft = Document.objects.get(name=draft.name)
389389
self.assertEqual(draft.get_state_slug("draft-iesg"), "ann")
390-
self.assertEqual(len(outbox), mailbox_before + 4)
390+
self.assertEqual(len(outbox), mailbox_before + 3)
391391
self.assertTrue("Protocol Action" in outbox[-2]['Subject'])
392392
# the IANA copy
393393
self.assertTrue("Protocol Action" in outbox[-1]['Subject'])
@@ -409,7 +409,7 @@ def test_disapprove_ballot(self):
409409

410410
draft = Document.objects.get(name=draft.name)
411411
self.assertEqual(draft.get_state_slug("draft-iesg"), "dead")
412-
self.assertEqual(len(outbox), mailbox_before + 3)
412+
self.assertEqual(len(outbox), mailbox_before + 2)
413413
self.assertTrue("NOT be published" in str(outbox[-1]))
414414

415415

@@ -441,11 +441,11 @@ def test_make_last_call(self):
441441
draft = Document.objects.get(name=draft.name)
442442
self.assertEqual(draft.get_state_slug("draft-iesg"), "lc")
443443
self.assertEqual(draft.latest_event(LastCallDocEvent, "sent_last_call").expires.strftime("%Y-%m-%d"), expire_date)
444-
self.assertEqual(len(outbox), mailbox_before + 4)
444+
self.assertEqual(len(outbox), mailbox_before + 3)
445445

446-
self.assertTrue("Last Call" in outbox[-4]['Subject'])
447-
# the IANA copy
448446
self.assertTrue("Last Call" in outbox[-3]['Subject'])
447+
# the IANA copy
448+
self.assertTrue("Last Call" in outbox[-2]['Subject'])
449449
self.assertTrue("Last Call" in draft.message_set.order_by("-time")[0].subject)
450450

451451
class DeferUndeferTestCase(TestCase):

ietf/doc/tests_draft.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,8 @@ def test_change_state(self):
7272
self.assertEqual(draft.docevent_set.count(), events_before + 2)
7373
self.assertTrue("Test comment" in draft.docevent_set.all()[0].desc)
7474
self.assertTrue("IESG state changed" in draft.docevent_set.all()[1].desc)
75-
self.assertEqual(len(outbox), mailbox_before + 2)
76-
self.assertTrue("State Update Notice" in outbox[-2]['Subject'])
77-
self.assertTrue(draft.name in outbox[-1]['Subject'])
75+
self.assertEqual(len(outbox), mailbox_before + 1)
76+
self.assertTrue("State Update Notice" in outbox[-1]['Subject'])
7877

7978

8079
# check that we got a previous state now
@@ -101,7 +100,7 @@ def test_pull_from_rfc_queue(self):
101100

102101
draft = Document.objects.get(name=draft.name)
103102
self.assertEqual(draft.get_state_slug("draft-iesg"), "review-e")
104-
self.assertEqual(len(outbox), mailbox_before + 2 + 1)
103+
self.assertEqual(len(outbox), mailbox_before + 2)
105104
self.assertTrue(draft.name in outbox[-1]['Subject'])
106105
self.assertTrue("changed state" in outbox[-1]['Subject'])
107106
self.assertTrue("is no longer" in str(outbox[-1]))
@@ -1095,7 +1094,7 @@ def test_adopt_document(self):
10951094
self.assertEqual(draft.notify,"aliens@example.mars")
10961095
self.assertEqual(len(outbox), mailbox_before + 1)
10971096
self.assertTrue("state changed" in outbox[-1]["Subject"].lower())
1098-
self.assertTrue("marschairman@ietf.org" in unicode(outbox[-1]))
1097+
self.assertTrue("mars-chairs@ietf.org" in unicode(outbox[-1]))
10991098
self.assertTrue("marsdelegate@ietf.org" in unicode(outbox[-1]))
11001099

11011100
self.assertFalse(mars.list_email in draft.notify)
@@ -1137,7 +1136,7 @@ def test_set_tags(self):
11371136
self.assertEqual(draft.docevent_set.count() - events_before, 2)
11381137
self.assertEqual(len(outbox), mailbox_before + 1)
11391138
self.assertTrue("tags changed" in outbox[-1]["Subject"].lower())
1140-
self.assertTrue("marschairman@ietf.org" in unicode(outbox[-1]))
1139+
self.assertTrue("mars-chairs@ietf.org" in unicode(outbox[-1]))
11411140
self.assertTrue("marsdelegate@ietf.org" in unicode(outbox[-1]))
11421141
self.assertTrue("plain@example.com" in unicode(outbox[-1]))
11431142

@@ -1181,7 +1180,7 @@ def test_set_state(self):
11811180
self.assertTrue(due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1))
11821181
self.assertEqual(len(outbox), mailbox_before + 1)
11831182
self.assertTrue("state changed" in outbox[-1]["Subject"].lower())
1184-
self.assertTrue("marschairman@ietf.org" in unicode(outbox[-1]))
1183+
self.assertTrue("mars-chairs@ietf.org" in unicode(outbox[-1]))
11851184
self.assertTrue("marsdelegate@ietf.org" in unicode(outbox[-1]))
11861185

11871186
class ChangeReplacesTests(TestCase):

ietf/doc/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
from ietf.ietfauth.utils import has_role
1919
from ietf.utils import draft, markup_txt
2020
from ietf.utils.mail import send_mail
21+
from ietf.mailtoken.utils import gather_address_list
2122

22-
#FIXME - it would be better if this lived in ietf/doc/mails.py, but there's
23+
#TODO FIXME - it would be better if this lived in ietf/doc/mails.py, but there's
2324
# an import order issue to work out.
2425
def email_update_telechat(request, doc, text):
25-
to = set(['iesg@ietf.org','iesg-secretary@ietf.org'])
26-
to.update(set([x.strip() for x in doc.notify.replace(';', ',').split(',')]))
26+
to = gather_address_list('doc_telechat_details_changed',doc=doc)
2727

2828
if not to:
2929
return
3030

3131
text = strip_tags(text)
32-
send_mail(request, list(to), None,
32+
send_mail(request, to, None,
3333
"Telechat update notice: %s" % doc.file_tag(),
3434
"doc/mail/update_telechat.txt",
3535
dict(text=text,

ietf/doc/views_ballot.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
BallotType, LastCallDocEvent, WriteupDocEvent, save_document_in_history, IESG_SUBSTATE_TAGS )
1818
from ietf.doc.utils import ( add_state_change_event, close_ballot, close_open_ballots,
1919
create_ballot_if_not_open, update_telechat )
20-
from ietf.doc.mails import ( email_ad, email_ballot_deferred, email_ballot_undeferred,
20+
from ietf.doc.mails import ( email_ballot_deferred, email_ballot_undeferred,
2121
email_state_changed, extra_automation_headers, generate_last_call_announcement,
2222
generate_issue_ballot_mail, generate_ballot_writeup, generate_approval_mail )
2323
from ietf.doc.lastcall import request_last_call
@@ -464,7 +464,6 @@ def lastcalltext(request, name):
464464

465465
if e:
466466
email_state_changed(request, doc, e.desc)
467-
email_ad(request, doc, doc.ad, login, e.desc)
468467

469468
request_last_call(request, doc)
470469

@@ -708,7 +707,6 @@ def approve_ballot(request, name):
708707
doc.save()
709708

710709
email_state_changed(request, doc, change_description)
711-
email_ad(request, doc, doc.ad, login, change_description)
712710

713711
# send announcement
714712

@@ -790,7 +788,6 @@ def make_last_call(request, name):
790788
change_description = "Last call has been made for %s and state has been changed to %s" % (doc.name, new_state.name)
791789

792790
email_state_changed(request, doc, change_description)
793-
email_ad(request, doc, doc.ad, login, change_description)
794791

795792
e = LastCallDocEvent(doc=doc, by=login)
796793
e.type = "sent_last_call"

ietf/doc/views_doc.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@
5151
needed_ballot_positions, nice_consensus, prettify_std_name, update_telechat, has_same_ballot,
5252
get_initial_notify, make_notify_changed_event )
5353
from ietf.community.models import CommunityList
54-
from ietf.doc.mails import email_ad
5554
from ietf.group.models import Role
5655
from ietf.group.utils import can_manage_group_type, can_manage_materials
5756
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_person, role_required
5857
from ietf.name.models import StreamName, BallotPositionName
5958
from ietf.person.models import Email
6059
from ietf.utils.history import find_history_active_at
6160
from ietf.doc.forms import TelechatForm, NotifyForm
61+
from ietf.doc.mails import email_ad
6262

6363
def render_document_top(request, doc, tab, name):
6464
tabs = []
@@ -878,6 +878,7 @@ def add_comment(request, name):
878878
e.save()
879879

880880
if doc.type_id == "draft":
881+
# TODO - build an explicit message for when a comment is added
881882
email_ad(request, doc, doc.ad, login,
882883
"A new comment added by %s" % login.name)
883884
return redirect("doc_history", name=doc.name)

ietf/doc/views_draft.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ def change_state(request, name):
111111
doc.save()
112112

113113
email_state_changed(request, doc, msg)
114-
email_ad(request, doc, doc.ad, login, msg)
115114

116115

117116
if prev_state and prev_state.slug in ("ann", "rfcqueue") and new_state.slug not in ("rfcqueue", "pub"):
@@ -450,6 +449,7 @@ def change_intention(request, name):
450449
doc.time = e.time
451450
doc.save()
452451

452+
# TODO: Build explicit changed_intended_publication_status
453453
email_ad(request, doc, doc.ad, login, email_desc)
454454

455455
return HttpResponseRedirect(doc.get_absolute_url())
@@ -726,6 +726,7 @@ def diff(attr, name):
726726
doc.time = datetime.datetime.now()
727727

728728
if changes and not new_document:
729+
#TODO - use the 'this thing changed' messages instead
729730
email_ad(request, doc, orig_ad, login, "\n".join(changes))
730731

731732
doc.save()

ietf/group/mails.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from ietf.utils.mail import send_mail, send_mail_text
1313
from ietf.group.models import Group
1414
from ietf.group.utils import milestone_reviewer_for_group_type
15+
from ietf.mailtoken.utils import gather_address_list
1516

1617
def email_iesg_secretary_re_charter(request, group, subject, text):
1718
to = ["iesg-secretary@ietf.org"]
@@ -77,26 +78,18 @@ def wrap_up_email(to, text):
7778

7879
send_mail_text(request, to, None, subject, text)
7980

80-
# first send to management and chairs
81-
to = []
82-
if group.ad_role():
83-
to.append(group.ad_role().email.formatted_email())
84-
elif group.type_id == "rg":
85-
to.append("IRTF Chair <irtf-chair@irtf.org>")
86-
87-
for r in group.role_set.filter(name="chair"):
88-
to.append(r.formatted_email())
89-
81+
# first send to those who should see any edits (such as management and chairs)
82+
to = gather_address_list('group_milestones_edited',group=group)
9083
if to:
9184
wrap_up_email(to, u"\n\n".join(c + "." for c in changes))
9285

93-
# then send to group
94-
if group.list_email:
95-
review_re = re.compile("Added .* for review, due")
96-
to = [ group.list_email ]
97-
msg = u"\n\n".join(c + "." for c in changes if not review_re.match(c))
98-
if msg:
99-
wrap_up_email(to, msg)
86+
# then send only the approved milestones to those who shouldn't be
87+
# bothered with milestones pending approval
88+
review_re = re.compile("Added .* for review, due")
89+
to = gather_address_list('group_approved_milestones_edited',group=group)
90+
msg = u"\n\n".join(c + "." for c in changes if not review_re.match(c))
91+
if to and msg:
92+
wrap_up_email(to, msg)
10093

10194

10295
def email_milestone_review_reminder(group, grace_period=7):

ietf/mailtoken/migrations/0002_auto_20150809_1314.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ def make_recipients(apps):
3737
desc="The document's group chairs (if the document is assigned to a working or research group)",
3838
template=None)
3939

40+
rc(slug='doc_group_delegates',
41+
desc="The document's group delegates (if the document is assigned to a working or research group)",
42+
template=None)
43+
4044
rc(slug='doc_affecteddoc_authors',
4145
desc="The authors of the subject documents of a conflict-review or status-change",
4246
template=None)
@@ -105,6 +109,9 @@ def make_recipients(apps):
105109
desc="The group's chairs",
106110
template="{{group.acronym}}-chairs@ietf.org")
107111

112+
rc(slug='group_responsible_directors',
113+
desc="The group's responsible AD(s) or IRTF chair",
114+
template=None)
108115

109116
def make_mailtokens(apps):
110117

@@ -300,7 +307,51 @@ def mt_factory(slug,desc,recipient_slugs):
300307
recipient_slugs=['stream_managers',
301308
'doc_notify',
302309
])
310+
311+
mt_factory(slug='doc_stream_state_edited',
312+
desc="Recipients when the stream state of a document is manually edited",
313+
recipient_slugs=['doc_group_chairs',
314+
'doc_group_delegates',
315+
'doc_shepherd',
316+
'doc_authors',
317+
])
318+
319+
mt_factory(slug='group_milestones_edited',
320+
desc="Recipients when any of a group's milestones are edited",
321+
recipient_slugs=['group_responsible_directors',
322+
'group_chairs',
323+
])
303324

325+
mt_factory(slug='group_approved_milestones_edited',
326+
desc="Recipients when the set of approved milestones for a group are edited",
327+
recipient_slugs=['group_mail_list',
328+
])
329+
330+
mt_factory(slug='doc_state_edited',
331+
desc="Recipients when a document's state is manutally edited",
332+
recipient_slugs=['doc_notify',
333+
'doc_ad',
334+
'doc_authors',
335+
'doc_shepherd',
336+
'doc_group_chairs',
337+
'doc_affecteddoc_authors',
338+
'doc_affecteddoc_group_chairs',
339+
'doc_affecteddoc_notify',
340+
])
341+
342+
mt_factory(slug='doc_telechat_details_changed',
343+
desc="Recipients when a document's telechat date or other telechat specific details are changed",
344+
recipient_slugs=['iesg',
345+
'iesg-secretary',
346+
'doc_notify',
347+
'doc_authors',
348+
'doc_shepherd',
349+
'doc_group_chairs',
350+
'doc_affecteddoc_authors',
351+
'doc_affecteddoc_group_chairs',
352+
'doc_affecteddoc_notify',
353+
])
354+
304355

305356
def forward(apps, schema_editor):
306357

0 commit comments

Comments
 (0)