checkpoint.

- Legacy-Id: 10011
This commit is contained in:
Robert Sparks 2015-08-11 21:52:28 +00:00
parent 15538ded7e
commit 79d373fa71
14 changed files with 106 additions and 44 deletions

View file

@ -30,13 +30,12 @@ def email_state_changed(request, doc, text):
def email_stream_changed(request, doc, old_stream, new_stream, text=""):
"""Email the change text to the notify group and to the stream chairs"""
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
# These use comprehension to deal with conditions when there might be more than one chair listed for a stream
streams = []
if old_stream:
to.extend([r.formatted_email() for r in Role.objects.filter(group__acronym=old_stream.slug, name='chair')])
streams.append(old_stream.slug)
if new_stream:
to.extend([r.formatted_email() for r in Role.objects.filter(group__acronym=new_stream.slug, name='chair')])
streams.append(new_stream.slug)
to = gather_addresses('doc_stream_changed',doc=doc,streams=streams)
if not to:
return
@ -124,8 +123,8 @@ def generate_last_call_announcement(request, doc):
dict(doc=doc,
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url() + "ballot/",
expiration_date=expiration_date.strftime("%Y-%m-%d"), #.strftime("%B %-d, %Y"),
to=",\n ".join(gather_addresses('last_call_issued',doc=doc)),
cc=",\n ".join(gather_addresses('last_call_issued_cc',doc=doc)),
to=gather_addresses('last_call_issued',doc=doc),
cc=gather_addresses('last_call_issued_cc',doc=doc),
group=group,
docs=[ doc ],
urls=[ settings.IDTRACKER_BASE_URL + doc.get_absolute_url() ],
@ -169,9 +168,6 @@ def generate_approval_mail_approved(request, doc):
else:
action_type = "Document"
to = gather_addresses('ballot_approved_ietf_stream',doc=doc)
cc = gather_addresses('ballot_approved_ietf_stream_cc',doc=doc)
# the second check catches some area working groups (like
# Transport Area Working Group)
if doc.group.type_id not in ("area", "individ", "ag") and not doc.group.name.endswith("Working Group"):
@ -202,8 +198,8 @@ def generate_approval_mail_approved(request, doc):
dict(doc=doc,
docs=[doc],
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
to=",\n ".join(to),
cc=",\n ".join(cc),
to = gather_addresses('ballot_approved_ietf_stream',doc=doc),
cc = gather_addresses('ballot_approved_ietf_stream_cc',doc=doc),
doc_type=doc_type,
made_by=made_by,
contacts=contacts,
@ -215,16 +211,13 @@ def generate_approval_mail_rfc_editor(request, doc):
disapproved = doc.get_state_slug("draft-iesg") in DO_NOT_PUBLISH_IESG_STATES
doc_type = "RFC" if doc.get_state_slug() == "rfc" else "Internet Draft"
to = gather_addresses('ballot_approved_conflrev', doc=doc)
cc = gather_addresses('ballot_approved_conflrev_cc', doc=doc)
return render_to_string("doc/mail/approval_mail_rfc_editor.txt",
dict(doc=doc,
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
doc_type=doc_type,
disapproved=disapproved,
to=",\n ".join(to),
cc=",\n ".join(cc),
to = gather_addresses('ballot_approved_conflrev', doc=doc),
cc = gather_addresses('ballot_approved_conflrev_cc', doc=doc),
)
)

View file

@ -15,7 +15,6 @@ from ietf.utils.test_utils import TestCase
from ietf.utils.mail import outbox
from ietf.utils.test_data import make_test_data
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.mailtoken.utils import gather_addresses
class EditPositionTests(TestCase):
@ -171,8 +170,8 @@ class EditPositionTests(TestCase):
r = self.client.post(url, dict(cc=""))
self.assertEqual(r.status_code, 302)
self.assertEqual(len(outbox), mailbox_before + 2)
m = outbox[-1]
self.assertEqual(m['Cc'],','.join(gather_addresses('ballot_saved_cc',doc=draft)))
#TODO this would be a good place to test actual mailtoken expansions
#if we can find a way to get the real, or at least representative, data in place.
class BallotWriteupsTests(TestCase):

View file

@ -70,7 +70,6 @@ class ConflictReviewTests(TestCase):
self.assertTrue(review_doc.latest_event(DocEvent,type="added_comment").desc.startswith("IETF conflict review requested"))
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith("IETF conflict review initiated"))
self.assertTrue('Conflict Review requested' in outbox[-1]['Subject'])
self.assertTrue(settings.IANA_EVAL_EMAIL in outbox[-1]['To'])
# verify you can't start a review when a review is already in progress
r = self.client.post(url,dict(ad="Aread Irector",create_in_state="Needs Shepherd",notify='ipu@ietf.org'))
@ -118,8 +117,8 @@ class ConflictReviewTests(TestCase):
self.assertTrue(doc in [x.target.document for x in review_doc.relateddocument_set.filter(relationship__slug='conflrev')])
self.assertEqual(len(outbox), messages_before + 2)
self.assertTrue('Conflict Review requested' in outbox[-1]['Subject'])
self.assertTrue(any('iesg-secretary@ietf.org' in x['To'] for x in outbox[-2:]))
self.assertTrue(any(settings.IANA_EVAL_EMAIL in x['To'] for x in outbox[-2:]))
#self.assertTrue(any('iesg-secretary@ietf.org' in x['To'] for x in outbox[-2:]))
#self.assertTrue(any(settings.IANA_EVAL_EMAIL in x['To'] for x in outbox[-2:]))
def test_change_state(self):

View file

@ -127,8 +127,8 @@ def default_action_text(group, charter, by):
techadv=group.role_set.filter(name="techadv"),
milestones=group.groupmilestone_set.filter(state="charter"),
action_type=action,
to=",\n ".join(gather_addresses('ballot_approved_charter',doc=charter,group=group)),
cc=",\n ".join(gather_addresses('ballot_approved_charter_cc',doc=charter,group=group)),
to=gather_addresses('ballot_approved_charter',doc=charter,group=group),
cc=gather_addresses('ballot_approved_charter_cc',doc=charter,group=group),
))
e.save()
@ -149,6 +149,8 @@ def default_review_text(group, charter, by):
milestones=group.groupmilestone_set.filter(state="charter"),
review_date=(datetime.date.today() + datetime.timedelta(weeks=1)).isoformat(),
review_type="new" if group.state_id == "proposed" else "recharter",
to=gather_addresses('charter_external_review',group=group),
cc=gather_addresses('charter_external_review_cc',group=group)
)
)
e.save()

View file

@ -27,7 +27,7 @@ from ietf.message.utils import infer_message
from ietf.name.models import BallotPositionName
from ietf.person.models import Person
from ietf.utils.mail import send_mail_text, send_mail_preformatted
from ietf.mailtoken.utils import gather_addresses
from ietf.mailtoken.utils import gather_addresses, gather_address_list
BALLOT_CHOICES = (("yes", "Yes"),
("noobj", "No Objection"),
@ -288,7 +288,7 @@ def send_ballot_comment(request, name, ballot_id):
to = gather_addresses('ballot_saved',doc=doc)
if request.method == 'POST':
cc = gather_addresses('ballot_saved_cc',doc=doc)
cc = gather_address_list('ballot_saved_cc',doc=doc)
explicit_cc = [x.strip() for x in request.POST.get("cc", "").split(',') if x.strip()]
if explicit_cc:
cc.extend(explicit_cc)
@ -716,7 +716,7 @@ def approve_ballot(request, name):
if action == "to_announcement_list":
send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc),
override={ "To": ",".join(gather_addresses('ballot_approved_ietf_stream_iana')), "CC": None, "Bcc": None, "Reply-To": None})
override={ "To": gather_addresses('ballot_approved_ietf_stream_iana'), "CC": None, "Bcc": None, "Reply-To": None})
msg = infer_message(announcement)
msg.by = login
@ -758,7 +758,7 @@ def make_last_call(request, name):
send_mail_preformatted(request, announcement)
if doc.type.slug == 'draft':
send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc),
override={ "To": ",\n ".join(gather_addresses('last_call_issued_iana',doc=doc)),
override={ "To": gather_addresses('last_call_issued_iana',doc=doc),
"CC": None, "Bcc": None, "Reply-To": None})
msg = infer_message(announcement)

View file

@ -20,6 +20,7 @@ from ietf.ietfauth.utils import has_role, role_required, is_authorized_in_doc_st
from ietf.person.models import Person
from ietf.utils.mail import send_mail_preformatted
from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.mailtoken.utils import gather_addresses
class ChangeStateForm(forms.Form):
review_state = forms.ModelChoiceField(State.objects.filter(used=True, type="conflrev"), label="Conflict review state", empty_label=None, required=True)
@ -88,6 +89,8 @@ def change_state(request, name, option=None):
def send_conflict_review_started_email(request, review):
msg = render_to_string("doc/conflict_review/review_started.txt",
dict(frm = settings.DEFAULT_FROM_EMAIL,
to = gather_addresses('conflrev_requested',doc=review),
cc = gather_addresses('conflrev_requested_cc',doc=review),
by = request.user.person,
review = review,
reviewed_doc = review.relateddocument_set.get(relationship__slug='conflrev').target.document,
@ -98,8 +101,8 @@ def send_conflict_review_started_email(request, review):
send_mail_preformatted(request,msg)
email_iana(request,
review.relateddocument_set.get(relationship__slug='conflrev').target.document,
settings.IANA_EVAL_EMAIL,
msg)
gather_addresses('conflrev_requested_iana',doc=review),
msg)
def send_conflict_eval_email(request,review):
msg = render_to_string("doc/eval_email.txt",

View file

@ -583,9 +583,9 @@ def to_iesg(request,name):
doc.save()
extra = {}
extra['Cc'] = ",\n ".join(gather_addresses('pubreq_iesg_cc',doc=doc))
extra['Cc'] = gather_addresses('pubreq_iesg_cc',doc=doc)
send_mail(request=request,
to = ",\n ".join(gather_addresses('pubreq_iesg',doc=doc)),
to = gather_addresses('pubreq_iesg',doc=doc),
frm = login.formatted_email(),
subject = "Publication has been requested for %s-%s" % (doc.name,doc.rev),
template = "doc/submit_to_iesg_email.txt",
@ -1133,7 +1133,7 @@ def request_publication(request, name):
m = Message()
m.frm = request.user.person.formatted_email()
m.to = ",\n ".join(gather_addresses('pubreq_rfced',doc=doc))
m.to = gather_addresses('pubreq_rfced',doc=doc)
m.by = request.user.person
next_state = State.objects.get(used=True, type="draft-stream-%s" % doc.stream.slug, slug="rfc-edit")
@ -1163,7 +1163,7 @@ def request_publication(request, name):
send_mail_message(request, m)
# IANA copy
m.to = ", ".join(gather_addresses('pubreq_rfced_iana',doc=doc))
m.to = gather_addresses('pubreq_rfced_iana',doc=doc)
send_mail_message(request, m, extra=extra_automation_headers(doc))
e = DocEvent(doc=doc, type="requested_publication", by=request.user.person)
@ -1299,6 +1299,7 @@ def adopt_draft(request, name):
update_reminder(doc, "stream-s", e, due_date)
# TODO: Replace this with a message that's explicitly about the document adoption
email_stream_state_changed(request, doc, prev_state, new_state, by, comment)
# comment

View file

@ -299,8 +299,8 @@ def default_approval_text(status_change,relateddoc):
approved_text = current_text,
action=action,
newstatus=newstatus(relateddoc),
to=",\n ".join(gather_addresses('ballot_approved_status_change',doc=status_change)),
cc=",\n ".join(gather_addresses('ballot_approved_status_change_cc',doc=status_change)),
to=gather_addresses('ballot_approved_status_change',doc=status_change),
cc=gather_addresses('ballot_approved_status_change_cc',doc=status_change),
)
)

View file

@ -63,7 +63,11 @@ def make_recipients(apps):
rc(slug='doc_stream_manager',
desc="The manager of the document's stream",
template='{% if doc.stream_id == "ise" %}<rfc-ise@rfc-editor.org>{% endif %}{% if doc.stream_id == "irtf" %}<irtf-chair@irtf.org>{% endif %}{% if doc.stream_id == "ietf" %}<iesg@ietf.org>{% endif %}')
template=None )
rc(slug='stream_managers',
desc="The managers of any related streams",
template=None )
rc(slug='conflict_review_stream_manager',
desc="The stream manager of a document being reviewed for IETF stream conflicts",
@ -81,6 +85,10 @@ def make_recipients(apps):
desc="IANA's draft last call address",
template='IANA <drafts-lastcall@icann.org>')
rc(slug='iana_eval',
desc="IANA's draft evaluation address",
template='IANA <drafts-eval@icann.org>')
rc(slug='iana',
desc="IANA",
template='<iana@iana.org>')
@ -97,6 +105,7 @@ def make_recipients(apps):
desc="The group's chairs",
template="{{group.acronym}}-chairs@ietf.org")
def make_mailtokens(apps):
Recipient=apps.get_model('mailtoken','Recipient')
@ -261,6 +270,38 @@ def make_mailtokens(apps):
desc='Recipients for IANA message when a non-IETF stream manager requests publication',
recipient_slugs=['iana_approve',])
mt_factory(slug='charter_external_review',
desc='Recipients for a charter external review',
recipient_slugs=['ietf_announce',])
mt_factory(slug='charter_external_review_cc',
desc='Copied on a charter external review',
recipient_slugs=['group_mail_list',])
mt_factory(slug='conflrev_requested',
desc="Recipients for a stream manager's request for an IETF conflict review",
recipient_slugs=['iesg_secretary'])
mt_factory(slug='conflrev_requested_cc',
desc="Copied on a stream manager's request for an IETF conflict review",
recipient_slugs=['iesg',
'doc_notify',
'doc_affecteddoc_authors',
'doc_affecteddoc_group_chairs',
'doc_affecteddoc_notify',
])
mt_factory(slug='conflrev_requested_iana',
desc="Recipients for IANA message when a stream manager requests an IETF conflict review",
recipient_slugs=['iana_eval',])
mt_factory(slug='doc_stream_changed',
desc="Recipients for notification when a document's stream changes",
recipient_slugs=['stream_managers',
'doc_notify',
])
def forward(apps, schema_editor):
make_recipients(apps)

View file

@ -97,4 +97,21 @@ class Recipient(models.Model):
addrs.append(sg_map[kwargs['group'].type_id])
return addrs
def gather_stream_managers(self, **kwargs):
addrs = []
manager_map = dict(ise = '<rfc-ise@rfc-editor.org>',
irtf = '<irtf-chair@irtf.org>',
ietf = '<iesg@ietf.org>',
iab = '<iab-chair@iab.org>')
if 'streams' in kwargs:
for stream in kwargs['streams']:
if stream in manager_map:
addrs.append(manager_map[stream])
return addrs
def gather_doc_stream_manager(self, **kwargs):
addrs = []
if 'doc' in kwargs:
addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':[kwargs['doc'].stream_id]}))
return addrs

View file

@ -3,7 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist
from ietf.mailtoken.models import MailToken
def gather_addresses(slug,**kwargs):
def gather_address_list(slug,**kwargs):
addrs = []
@ -18,3 +18,6 @@ def gather_addresses(slug,**kwargs):
addrs.extend(recipient.gather(**kwargs))
return list(set(addrs))
def gather_addresses(slug,**kwargs):
return ",\n ".join(gather_address_list(slug,**kwargs))

View file

@ -1,6 +1,6 @@
{% load ietf_filters %}{% autoescape off %}From: The IESG <iesg-secretary@ietf.org>
To: IETF-Announce <ietf-announce@ietf.org>{% if group.list_email %}
Cc: {{ group.acronym }} {{ group.type.name }} <{{ group.list_email }}> {% endif %}
To: {{ to }}{% if cc %}
Cc: {{ cc }} {% endif %}
Subject: WG Review: {{ group.name }} ({{ group.acronym }})
{% filter wordwrap:73 %}{% if review_type == "new" %}A new IETF working group has been proposed in the {{ group.parent.name }}.{% endif %}{% if review_type == "recharter" %}The {{ group.name }} ({{group.acronym}}) working group in the {{ group.parent.name }} of the IETF is undergoing rechartering.{% endif %} The IESG has not made any determination yet. The following draft charter was submitted, and is provided for informational purposes only. Please send your comments to the IESG mailing list (iesg at ietf.org) by {{ review_date }}.

View file

@ -1,5 +1,6 @@
{% load mail_filters %}{% autoescape off %}To: IESG Secretary <iesg-secretary@ietf.org>
From: {{ frm }}
{% load mail_filters %}{% autoescape off %}To: {{to}}{% if cc %}
Cc: {{cc}}
{% endif %}From: {{ frm }}
Subject: Conflict Review requested for {{reviewed_doc.name}}
{{ by.name }} has requested a conflict review for:

View file

@ -335,8 +335,11 @@ def make_test_data():
# This won't allow testing the results of the production configuration - if we want to do that, we'll need to
# extract the production data either directly, or as a fixture
recipient = Recipient.objects.create(slug='bogus_recipient',desc='Bogus Recipient',template='bogus@example.com')
for slug in ['ballot_approved_charter', 'ballot_approved_charter_cc', 'ballot_approved_conflrev', 'ballot_approved_conflrev_cc', 'ballot_approved_ietf_stream', 'ballot_approved_ietf_stream_cc', 'ballot_approved_ietf_stream_iana', 'ballot_approved_status_change', 'ballot_approved_status_change_cc', 'ballot_deferred', 'ballot_saved', 'ballot_saved_cc', 'last_call_expired', 'last_call_expired_cc', 'last_call_issued', 'last_call_issued_cc', 'last_call_issued_iana', 'last_call_requested', 'last_call_requested_cc', 'pubreq_iesg', 'pubreq_iesg_cc', 'pubreq_rfced', 'pubreq_rfced_iana']:
for slug in ['ballot_approved_charter', 'ballot_approved_charter_cc', 'ballot_approved_conflrev', 'ballot_approved_conflrev_cc', 'ballot_approved_ietf_stream', 'ballot_approved_ietf_stream_cc', 'ballot_approved_ietf_stream_iana', 'ballot_approved_status_change', 'ballot_approved_status_change_cc', 'ballot_deferred', 'ballot_saved', 'ballot_saved_cc', 'charter_external_review', 'charter_external_review_cc', 'conflrev_requested', 'conflrev_requested_cc', 'conflrev_requested_iana', 'doc_stream_changed', 'last_call_expired', 'last_call_expired_cc', 'last_call_issued', 'last_call_issued_cc', 'last_call_issued_iana', 'last_call_requested', 'last_call_requested_cc', 'pubreq_iesg', 'pubreq_iesg_cc', 'pubreq_rfced', 'pubreq_rfced_iana']:
m = MailToken.objects.create(slug=slug,desc=slug)
m.recipients=[recipient]
# Well, this isn't working out so well - Recipients that have code backing up their gather sometimes refer to other Recipients...
for slug in ['doc_authors','doc_group_chairs','doc_notify','doc_stream_owner','stream_managers']:
Recipient.objects.create(slug=slug,desc="Bogus Recipient",template='bogus@example.com')
return draft