updated mailtoken utilities to match the model refactor. Morphed all the code using the utilities to match. Added paths to get Cc through as needed. Next up: Recipient selection form for the iesg save-and-send-email workflow

- Legacy-Id: 10040
This commit is contained in:
Robert Sparks 2015-08-23 18:15:06 +00:00
parent d16efcc6cf
commit 90c3426e2f
24 changed files with 331 additions and 231 deletions

View file

@ -10,8 +10,7 @@ from ietf.doc.models import Document, DocEvent, State, save_document_in_history,
from ietf.person.models import Person
from ietf.meeting.models import Meeting
from ietf.doc.utils import add_state_change_event
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
def expirable_draft(draft):
@ -71,8 +70,7 @@ def send_expire_warning_for_draft(doc):
expiration = doc.expires.date()
to = gather_address_list('doc_expires_soon',doc=doc)
cc = gather_address_list('doc_expires_soon_cc',doc=doc)
(to,cc) = gather_address_lists('doc_expires_soon',doc=doc)
s = doc.get_state("draft-iesg")
state = s.name if s else "I-D Exists"
@ -97,8 +95,7 @@ def send_expire_notice_for_draft(doc):
state = s.name if s else "I-D Exists"
request = None
to = gather_address_list('doc_expired',doc=doc)
cc = gather_address_list('doc_expired_cc',doc=doc)
(to,cc) = gather_address_lists('doc_expired',doc=doc)
send_mail(request, to,
"I-D Expiring System <ietf-secretariat-reply@ietf.org>",
u"I-D was expired %s" % doc.file_tag(),

View file

@ -14,10 +14,10 @@ from ietf.doc.utils import needed_ballot_positions
from ietf.person.models import Person
from ietf.group.models import Role
from ietf.doc.models import Document
from ietf.mailtoken.utils import gather_addresses, gather_address_list
from ietf.mailtoken.utils import gather_address_lists
def email_state_changed(request, doc, text, mailtoken_id=None):
to = gather_address_list(mailtoken_id or 'doc_state_edited',doc=doc)
(to,cc) = gather_address_lists(mailtoken_id or 'doc_state_edited',doc=doc)
if not to:
return
@ -26,7 +26,8 @@ def email_state_changed(request, doc, text, mailtoken_id=None):
"ID Tracker State Update Notice: %s" % doc.file_tag(),
"doc/mail/state_changed_email.txt",
dict(text=text,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc=cc)
def email_stream_changed(request, doc, old_stream, new_stream, text=""):
"""Email the change text to the notify group and to the stream chairs"""
@ -35,7 +36,7 @@ def email_stream_changed(request, doc, old_stream, new_stream, text=""):
streams.append(old_stream.slug)
if new_stream:
streams.append(new_stream.slug)
to = gather_address_list('doc_stream_changed',doc=doc,streams=streams)
(to,cc) = gather_address_lists('doc_stream_changed',doc=doc,streams=streams)
if not to:
return
@ -48,12 +49,14 @@ def email_stream_changed(request, doc, old_stream, new_stream, text=""):
"ID Tracker Stream Change Notice: %s" % doc.file_tag(),
"doc/mail/stream_changed_email.txt",
dict(text=text,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc=cc)
def email_pulled_from_rfc_queue(request, doc, comment, prev_state, next_state):
extra=extra_automation_headers(doc)
extra['Cc'] = gather_addresses('doc_pulled_from_rfc_queue_cc',doc=doc)
send_mail(request, gather_address_list('doc_pulled_from_rfc_queue',doc=doc), None,
addrs = gather_address_lists('doc_pulled_from_rfc_queue',doc=doc)
extra['Cc'] = addrs.as_strings().cc
send_mail(request, addrs.to , None,
"%s changed state from %s to %s" % (doc.name, prev_state.name, next_state.name),
"doc/mail/pulled_from_rfc_queue_email.txt",
dict(doc=doc,
@ -112,12 +115,14 @@ def generate_last_call_announcement(request, doc):
else:
ipr_links = None
addrs = gather_address_lists('last_call_issued',doc=doc).as_strings()
mail = render_to_string("doc/mail/last_call_announcement.txt",
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=gather_addresses('last_call_issued',doc=doc),
cc=gather_addresses('last_call_issued_cc',doc=doc),
to=addrs.to,
cc=addrs.cc,
group=group,
docs=[ doc ],
urls=[ settings.IDTRACKER_BASE_URL + doc.get_absolute_url() ],
@ -187,12 +192,13 @@ def generate_approval_mail_approved(request, doc):
doc_type = "RFC" if doc.get_state_slug() == "rfc" else "Internet Draft"
addrs = gather_address_lists('ballot_approved_ietf_stream',doc=doc).as_strings()
return render_to_string("doc/mail/approval_mail.txt",
dict(doc=doc,
docs=[doc],
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
to = gather_addresses('ballot_approved_ietf_stream',doc=doc),
cc = gather_addresses('ballot_approved_ietf_stream_cc',doc=doc),
to = addrs.to,
cc = addrs.cc,
doc_type=doc_type,
made_by=made_by,
contacts=contacts,
@ -205,14 +211,15 @@ def generate_approval_mail_rfc_editor(request, doc):
# which does not happen now that we have conflict reviews.
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"
addrs = gather_address_lists('ballot_approved_conflrev', doc=doc).as_strings()
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 = gather_addresses('ballot_approved_conflrev', doc=doc),
cc = gather_addresses('ballot_approved_conflrev_cc', doc=doc),
to = addrs.to,
cc = addrs.cc,
)
)
@ -242,8 +249,7 @@ def generate_publication_request(request, doc):
)
def send_last_call_request(request, doc):
to = gather_addresses('last_call_requested',doc=doc)
cc = gather_addresses('last_call_requested_cc',doc=doc)
(to, cc) = gather_address_lists('last_call_requested',doc=doc)
frm = '"DraftTracker Mail System" <iesg-secretary@ietf.org>'
send_mail(request, to, frm,
@ -255,7 +261,7 @@ def send_last_call_request(request, doc):
cc=cc)
def email_resurrect_requested(request, doc, by):
to = gather_address_list('resurrection_requested',doc=doc)
(to, cc) = gather_address_lists('resurrection_requested',doc=doc)
if by.role_set.filter(name="secr", group__acronym="secretariat"):
e = by.role_email("secr", group="secretariat")
@ -268,20 +274,22 @@ def email_resurrect_requested(request, doc, by):
"doc/mail/resurrect_request_email.txt",
dict(doc=doc,
by=frm,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc=cc)
def email_resurrection_completed(request, doc, requester):
to = gather_address_list('resurrection_completed',doc=doc)
(to, cc) = gather_address_lists('resurrection_completed',doc=doc)
frm = "I-D Administrator <internet-drafts-reply@ietf.org>"
send_mail(request, to, frm,
"I-D Resurrection Completed - %s" % doc.file_tag(),
"doc/mail/resurrect_completed_email.txt",
dict(doc=doc,
by=frm,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc=cc)
def email_ballot_deferred(request, doc, by, telechat_date):
to = gather_addresses('ballot_deferred',doc=doc)
(to, cc) = gather_address_lists('ballot_deferred',doc=doc)
frm = "DraftTracker Mail System <iesg-secretary@ietf.org>"
send_mail(request, to, frm,
"IESG Deferred Ballot notification: %s" % doc.file_tag(),
@ -289,10 +297,11 @@ def email_ballot_deferred(request, doc, by, telechat_date):
dict(doc=doc,
by=by,
action='deferred',
telechat_date=telechat_date))
telechat_date=telechat_date),
cc=cc)
def email_ballot_undeferred(request, doc, by, telechat_date):
to = gather_addresses('ballot_deferred',doc=doc)
(to, cc) = gather_address_lists('ballot_deferred',doc=doc)
frm = "DraftTracker Mail System <iesg-secretary@ietf.org>"
send_mail(request, to, frm,
"IESG Undeferred Ballot notification: %s" % doc.file_tag(),
@ -300,7 +309,8 @@ def email_ballot_undeferred(request, doc, by, telechat_date):
dict(doc=doc,
by=by,
action='undeferred',
telechat_date=telechat_date))
telechat_date=telechat_date),
cc=cc)
def generate_issue_ballot_mail(request, doc, ballot):
active_ads = Person.objects.filter(role__name="ad", role__group__state="active", role__group__type="area").distinct()
@ -370,7 +380,7 @@ def generate_issue_ballot_mail(request, doc, ballot):
)
)
def email_iana(request, doc, to, msg):
def email_iana(request, doc, to, msg, cc=None):
# fix up message and send it with extra info on doc in headers
import email
parsed_msg = email.message_from_string(msg.encode("utf-8"))
@ -383,7 +393,8 @@ def email_iana(request, doc, to, msg):
send_mail_text(request, "IANA <%s>" % to,
parsed_msg["From"], parsed_msg["Subject"],
parsed_msg.get_payload(),
extra=extra)
extra=extra,
cc=cc)
def extra_automation_headers(doc):
extra = {}
@ -394,24 +405,24 @@ def extra_automation_headers(doc):
def email_last_call_expired(doc):
text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.get_state("draft-iesg").name
addrs = gather_address_lists('last_call_expired',doc=doc)
send_mail(None,
gather_addresses('last_call_expired',doc=doc),
addrs.to,
"DraftTracker Mail System <iesg-secretary@ietf.org>",
"Last Call Expired: %s" % doc.file_tag(),
"doc/mail/change_notice.txt",
dict(text=text,
doc=doc,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc = gather_addresses('last_call_expired_cc',doc=doc)
)
cc = addrs.cc)
def email_stream_state_changed(request, doc, prev_state, new_state, by, comment=""):
recipients = gather_address_list('doc_stream_state_edited',doc=doc)
(to, cc)= gather_address_lists('doc_stream_state_edited',doc=doc)
state_type = (prev_state or new_state).type
send_mail(request, recipients, settings.DEFAULT_FROM_EMAIL,
send_mail(request, to, settings.DEFAULT_FROM_EMAIL,
u"%s changed for %s" % (state_type.label, doc.name),
'doc/mail/stream_state_changed_email.txt',
dict(doc=doc,
@ -420,13 +431,14 @@ def email_stream_state_changed(request, doc, prev_state, new_state, by, comment=
prev_state=prev_state,
new_state=new_state,
by=by,
comment=comment))
comment=comment),
cc=cc)
def email_stream_tags_changed(request, doc, added_tags, removed_tags, by, comment=""):
recipients = gather_address_list('doc_stream_state_edited',doc=doc)
(to, cc) = gather_address_lists('doc_stream_state_edited',doc=doc)
send_mail(request, recipients, settings.DEFAULT_FROM_EMAIL,
send_mail(request, to, settings.DEFAULT_FROM_EMAIL,
u"Tags changed for %s" % doc.name,
'doc/mail/stream_tags_changed_email.txt',
dict(doc=doc,
@ -434,32 +446,24 @@ def email_stream_tags_changed(request, doc, added_tags, removed_tags, by, commen
added=added_tags,
removed=removed_tags,
by=by,
comment=comment))
comment=comment),
cc=cc)
def send_review_possibly_replaces_request(request, doc):
to_email = []
if doc.stream_id == "ietf":
to_email.extend(r.formatted_email() for r in Role.objects.filter(group=doc.group, name="chair").select_related("email", "person"))
elif doc.stream_id == "iab":
to_email.append("IAB Stream <iab-stream@iab.org>")
elif doc.stream_id == "ise":
to_email.append("Independent Submission Editor <rfc-ise@rfc-editor.org>")
elif doc.stream_id == "irtf":
to_email.append("IRSG <irsg@irtf.org>")
addrs = gather_address_lists('doc_replacement_suggested',doc=doc)
to = set(addrs.to)
cc = set(addrs.cc)
possibly_replaces = Document.objects.filter(name__in=[alias.name for alias in doc.related_that_doc("possibly-replaces")])
other_chairs = Role.objects.filter(group__in=[other.group for other in possibly_replaces], name="chair").select_related("email", "person")
to_email.extend(r.formatted_email() for r in other_chairs)
for other_doc in possibly_replaces:
(other_to, other_cc) = gather_address_lists('doc_replacement_suggested',doc=other_doc)
to.update(other_to)
cc.update(other_cc)
if not to_email:
to_email.append("internet-drafts@ietf.org")
if to_email:
send_mail(request, list(set(to_email)), settings.DEFAULT_FROM_EMAIL,
'Review of suggested possible replacements for %s-%s needed' % (doc.name, doc.rev),
'doc/mail/review_possibly_replaces_request.txt', {
'doc': doc,
'possibly_replaces': doc.related_that_doc("possibly-replaces"),
'review_url': settings.IDTRACKER_BASE_URL + urlreverse("doc_review_possibly_replaces", kwargs={ "name": doc.name }),
})
send_mail(request, list(to), settings.DEFAULT_FROM_EMAIL,
'Review of suggested possible replacements for %s-%s needed' % (doc.name, doc.rev),
'doc/mail/review_possibly_replaces_request.txt',
dict(doc= doc,
possibly_replaces=doc.related_that_doc("possibly-replaces"),
review_url=settings.IDTRACKER_BASE_URL + urlreverse("doc_review_possibly_replaces", kwargs={ "name": doc.name })),
cc=list(cc),)

View file

@ -173,7 +173,7 @@ class EditPositionTests(TestCase):
self.assertEqual(len(outbox), mailbox_before + 2)
m = outbox[-1]
self.assertTrue("iesg@" in m['To'])
self.assertFalse(draft.group.list_email in m['Cc'])
self.assertFalse(m['Cc'] and draft.group.list_email in m['Cc'])
class BallotWriteupsTests(TestCase):

View file

@ -18,12 +18,12 @@ from ietf.group.models import Role
from ietf.ietfauth.utils import has_role
from ietf.utils import draft, markup_txt
from ietf.utils.mail import send_mail
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
#TODO FIXME - it would be better if this lived in ietf/doc/mails.py, but there's
# an import order issue to work out.
def email_update_telechat(request, doc, text):
to = gather_address_list('doc_telechat_details_changed',doc=doc)
(to, cc) = gather_address_lists('doc_telechat_details_changed',doc=doc)
if not to:
return
@ -33,7 +33,8 @@ def email_update_telechat(request, doc, text):
"Telechat update notice: %s" % doc.file_tag(),
"doc/mail/update_telechat.txt",
dict(text=text,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc=cc)
def get_state_types(doc):
res = []
@ -457,14 +458,18 @@ def rebuild_reference_relations(doc,filename=None):
return ret
def set_replaces_for_document(request, doc, new_replaces, by, email_subject, email_comment=""):
to = gather_address_list('doc_replacement_changed',doc=doc)
addrs = gather_address_lists('doc_replacement_changed',doc=doc)
to = set(addrs.to)
cc = set(addrs.cc)
relationship = DocRelationshipName.objects.get(slug='replaces')
old_replaces = doc.related_that_doc("replaces")
for d in old_replaces:
if d not in new_replaces:
to.extend(gather_address_list('doc_replacement_changed',doc=d.document))
other_addrs = gather_address_lists('doc_replacement_changed',doc=d.document)
to.update(other_addrs.to)
cc.update(other_addrs.cc)
RelatedDocument.objects.filter(source=doc, target=d, relationship=relationship).delete()
if not RelatedDocument.objects.filter(target=d, relationship=relationship):
s = 'active' if d.document.expires > datetime.datetime.now() else 'expired'
@ -472,7 +477,9 @@ def set_replaces_for_document(request, doc, new_replaces, by, email_subject, ema
for d in new_replaces:
if d not in old_replaces:
to.extend(gather_address_list('doc_replacement_changed',doc=d.document))
other_addrs = gather_address_lists('doc_replacement_changed',doc=d.document)
to.update(other_addrs.to)
cc.update(other_addrs.cc)
RelatedDocument.objects.create(source=doc, target=d, relationship=relationship)
d.document.set_state(State.objects.get(type='draft', slug='repl'))
@ -490,17 +497,16 @@ def set_replaces_for_document(request, doc, new_replaces, by, email_subject, ema
if email_comment:
email_desc += "\n" + email_comment
to = list(set([addr for addr in to if addr]))
from ietf.doc.mails import html_to_text
send_mail(request, to,
send_mail(request, list(to),
"DraftTracker Mail System <iesg-secretary@ietf.org>",
email_subject,
"doc/mail/change_notice.txt",
dict(text=html_to_text(email_desc),
doc=doc,
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
cc=list(cc))
def check_common_doc_name_rules(name):
"""Check common rules for document names for use in forms, throws

View file

@ -6,7 +6,7 @@ from django.conf import settings
from ietf.doc.models import NewRevisionDocEvent, WriteupDocEvent, BallotPositionDocEvent
from ietf.person.models import Person
from ietf.utils.history import find_history_active_at
from ietf.mailtoken.utils import gather_addresses
from ietf.mailtoken.utils import gather_address_lists
def charter_name_for_group(group):
if group.type_id == "rg":
@ -99,6 +99,7 @@ def default_action_text(group, charter, by):
else:
action = "Rechartered"
addrs = gather_address_lists('ballot_approved_charter',doc=charter,group=group).as_strings(compact=False)
e = WriteupDocEvent(doc=charter, by=by)
e.by = by
e.type = "changed_action_announcement"
@ -112,14 +113,15 @@ 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=gather_addresses('ballot_approved_charter',doc=charter,group=group),
cc=gather_addresses('ballot_approved_charter_cc',doc=charter,group=group),
to=addrs.to,
cc=addrs.cc,
))
e.save()
return e
def default_review_text(group, charter, by):
addrs=gather_address_lists('charter_external_review',group=group).as_strings(compact=False)
e = WriteupDocEvent(doc=charter, by=by)
e.by = by
e.type = "changed_review_announcement"
@ -134,8 +136,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)
to=addrs.to,
cc=addrs.cc,
)
)
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, gather_address_list
from ietf.mailtoken.utils import gather_address_lists
BALLOT_CHOICES = (("yes", "Yes"),
("noobj", "No Objection"),
@ -283,19 +283,20 @@ def send_ballot_comment(request, name, ballot_id):
blocking_name=blocking_name,
settings=settings))
frm = ad.role_email("ad").formatted_email()
to = gather_addresses('ballot_saved',doc=doc)
addrs = gather_address_lists('ballot_saved',doc=doc)
if request.method == 'POST':
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)
# The send_ballot_comments form provides an unusual case where the form separates out
# the cc addresses to be edited before sending into a separate field
# TODO: We should consider undoing this, and going back at most to an "extra_cc" model
cc = [x.strip() for x in request.POST.get("cc", "").split(',') if x.strip()]
if request.POST.get("cc_state_change") and doc.notify:
cc.extend(doc.notify.split(','))
if request.POST.get("cc_group_list") and doc.group.list_email:
cc.append(doc.group.list_email)
send_mail_text(request, to, frm, subject, body, cc=u", ".join(cc))
send_mail_text(request, addrs.to, frm, subject, body, cc=u", ".join(cc))
return HttpResponseRedirect(return_to_url)
@ -304,7 +305,8 @@ def send_ballot_comment(request, name, ballot_id):
subject=subject,
body=body,
frm=frm,
to=to,
to=addrs.as_strings().to,
cc=addrs.as_strings().cc,
ad=ad,
can_send=d or c,
back_url=back_url,
@ -701,8 +703,9 @@ def approve_ballot(request, name):
send_mail_preformatted(request, announcement)
if action == "to_announcement_list":
addrs = gather_address_lists('ballot_approved_ietf_stream_iana').as_strings(compact=False)
send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc),
override={ "To": gather_addresses('ballot_approved_ietf_stream_iana'), "CC": None, "Bcc": None, "Reply-To": None})
override={ "To": addrs.to, "CC": addrs.cc, "Bcc": None, "Reply-To": None})
msg = infer_message(announcement)
msg.by = login
@ -743,9 +746,9 @@ def make_last_call(request, name):
if form.is_valid():
send_mail_preformatted(request, announcement)
if doc.type.slug == 'draft':
addrs = gather_address_lists('last_call_issued_iana',doc=doc).as_strings(compact=False)
send_mail_preformatted(request, announcement, extra=extra_automation_headers(doc),
override={ "To": gather_addresses('last_call_issued_iana',doc=doc),
"CC": None, "Bcc": None, "Reply-To": None})
override={ "To": addrs.to, "CC": addrs.cc, "Bcc": None, "Reply-To": None})
msg = infer_message(announcement)
msg.by = login

View file

@ -20,7 +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
from ietf.mailtoken.utils import gather_address_lists
class ChangeStateForm(forms.Form):
review_state = forms.ModelChoiceField(State.objects.filter(used=True, type="conflrev"), label="Conflict review state", empty_label=None, required=True)
@ -87,10 +87,11 @@ def change_state(request, name, option=None):
context_instance=RequestContext(request))
def send_conflict_review_started_email(request, review):
addrs = gather_address_lists('conflrev_requested',doc=review).as_strings(compact=False)
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),
to = addrs.to,
cc = addrs.cc,
by = request.user.person,
review = review,
reviewed_doc = review.relateddocument_set.get(relationship__slug='conflrev').target.document,
@ -99,10 +100,13 @@ def send_conflict_review_started_email(request, review):
)
if not has_role(request.user,"Secretariat"):
send_mail_preformatted(request,msg)
addrs = gather_address_lists('conflrev_requested_iana',doc=review).as_strings(compact=False)
email_iana(request,
review.relateddocument_set.get(relationship__slug='conflrev').target.document,
gather_addresses('conflrev_requested_iana',doc=review),
msg)
addrs.to,
msg,
cc=addrs.cc)
def send_conflict_eval_email(request,review):
msg = render_to_string("doc/eval_email.txt",
@ -254,6 +258,7 @@ def default_approval_text(review):
receiver = 'IRTF'
else:
receiver = 'recipient'
addrs = gather_address_lists('ballot_approved_conflrev',doc=review).as_strings(compact=False)
text = render_to_string("doc/conflict_review/approval_text.txt",
dict(review=review,
review_url = settings.IDTRACKER_BASE_URL+review.get_absolute_url(),
@ -261,8 +266,8 @@ def default_approval_text(review):
conflictdoc_url = settings.IDTRACKER_BASE_URL+conflictdoc.get_absolute_url(),
receiver=receiver,
approved_review = current_text,
to = gather_addresses('ballot_approved_conflrev',doc=review),
cc = gather_addresses('ballot_approved_conflrev_cc',doc=review),
to = addrs.to,
cc = addrs.cc,
)
)

View file

@ -37,7 +37,7 @@ from ietf.person.models import Person, Email
from ietf.secr.lib.template import jsonapi
from ietf.utils.mail import send_mail, send_mail_message
from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.mailtoken.utils import gather_addresses
from ietf.mailtoken.utils import gather_address_lists
class ChangeStateForm(forms.Form):
state = forms.ModelChoiceField(State.objects.filter(used=True, type="draft-iesg"), empty_label=None, required=True)
@ -582,10 +582,11 @@ def to_iesg(request,name):
doc.save()
addrs= gather_address_lists('pubreq_iesg',doc=doc)
extra = {}
extra['Cc'] = gather_addresses('pubreq_iesg_cc',doc=doc)
extra['Cc'] = addrs.as_strings().cc
send_mail(request=request,
to = gather_addresses('pubreq_iesg',doc=doc),
to = addrs.to,
frm = login.formatted_email(),
subject = "Publication has been requested for %s-%s" % (doc.name,doc.rev),
template = "doc/submit_to_iesg_email.txt",
@ -1134,7 +1135,7 @@ def request_publication(request, name):
m = Message()
m.frm = request.user.person.formatted_email()
m.to = gather_addresses('pubreq_rfced',doc=doc)
(m.to, m.cc) = gather_address_lists('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")
@ -1164,7 +1165,7 @@ def request_publication(request, name):
send_mail_message(request, m)
# IANA copy
m.to = gather_addresses('pubreq_rfced_iana',doc=doc)
(m.to, m.cc) = gather_address_lists('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)

View file

@ -22,7 +22,7 @@ from ietf.name.models import DocRelationshipName, StdLevelName
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
from ietf.mailtoken.utils import gather_address_lists
class ChangeStateForm(forms.Form):
new_state = forms.ModelChoiceField(State.objects.filter(type="statchg", used=True), label="Status Change Evaluation State", empty_label=None, required=True)
@ -290,7 +290,8 @@ def default_approval_text(status_change,relateddoc):
else:
action = "Document Action"
addrs = gather_address_lists('ballot_approved_status_change',doc=status_change).as_strings(compact=False)
text = render_to_string("doc/status_change/approval_text.txt",
dict(status_change=status_change,
status_change_url = settings.IDTRACKER_BASE_URL+status_change.get_absolute_url(),
@ -299,8 +300,8 @@ def default_approval_text(status_change,relateddoc):
approved_text = current_text,
action=action,
newstatus=newstatus(relateddoc),
to=gather_addresses('ballot_approved_status_change',doc=status_change),
cc=gather_addresses('ballot_approved_status_change_cc',doc=status_change),
to=addrs.to,
cc=addrs.cc,
)
)

View file

@ -12,10 +12,10 @@ from django.core.urlresolvers import reverse as urlreverse
from ietf.utils.mail import send_mail, send_mail_text
from ietf.group.models import Group
from ietf.group.utils import milestone_reviewer_for_group_type
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
def email_admin_re_charter(request, group, subject, text, mailtoken):
to = gather_address_list(mailtoken,group=group)
(to,cc) = gather_address_lists(mailtoken,group=group)
full_subject = u"Regarding %s %s: %s" % (group.type.name, group.acronym, subject)
text = strip_tags(text)
@ -25,17 +25,18 @@ def email_admin_re_charter(request, group, subject, text, mailtoken):
group=group,
group_url=settings.IDTRACKER_BASE_URL + group.about_url(),
charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=group.charter.name)) if group.charter else "[no charter]",
)
)
),
cc=cc,
)
def email_personnel_change(request, group, text, changed_personnel):
to = gather_address_list('group_personnel_change',group=group,changed_personnel=changed_personnel)
(to, cc) = gather_address_lists('group_personnel_change',group=group,changed_personnel=changed_personnel)
full_subject = u"Personnel change for %s working group" % (group.acronym)
send_mail_text(request, to, None, full_subject,text)
send_mail_text(request, to, None, full_subject, text, cc=cc)
def email_milestones_changed(request, group, changes):
def wrap_up_email(to, text):
def wrap_up_email(addrs, text):
subject = u"Milestones changed for %s %s" % (group.acronym, group.type.name)
if re.search("Added .* for review, due",text):
@ -45,26 +46,25 @@ def email_milestones_changed(request, group, changes):
text += "\n\n"
text += u"URL: %s" % (settings.IDTRACKER_BASE_URL + group.about_url())
send_mail_text(request, to, None, subject, text)
send_mail_text(request, addrs.to, None, subject, text, cc=addrs.cc)
# first send to those who should see any edits (such as management and chairs)
to = gather_address_list('group_milestones_edited',group=group)
if to:
wrap_up_email(to, u"\n\n".join(c + "." for c in changes))
addrs = gather_address_lists('group_milestones_edited',group=group)
if addrs.to or addrs.cc:
wrap_up_email(addrs, u"\n\n".join(c + "." for c in changes))
# then send only the approved milestones to those who shouldn't be
# bothered with milestones pending approval
review_re = re.compile("Added .* for review, due")
to = gather_address_list('group_approved_milestones_edited',group=group)
addrs = gather_address_lists('group_approved_milestones_edited',group=group)
msg = u"\n\n".join(c + "." for c in changes if not review_re.match(c))
if to and msg:
wrap_up_email(to, msg)
if (addrs.to or addrs.cc) and msg:
wrap_up_email(addrs, msg)
def email_milestone_review_reminder(group, grace_period=7):
"""Email reminders about milestones needing review to management."""
to = gather_address_list('milestone_review_reminder',group=group)
cc = gather_address_list('milestone_review_reminder_cc',group=group)
(to, cc) = gather_address_lists('milestone_review_reminder',group=group)
if not to:
return False
@ -102,7 +102,7 @@ def groups_with_milestones_needing_review():
return Group.objects.filter(groupmilestone__state="review").distinct()
def email_milestones_due(group, early_warning_days):
to = gather_address_list('milestones_due_soon',group=group)
(to, cc) = gather_address_lists('milestones_due_soon',group=group)
today = datetime.date.today()
early_warning = today + datetime.timedelta(days=early_warning_days)
@ -120,7 +120,9 @@ def email_milestones_due(group, early_warning_days):
today=today,
early_warning_days=early_warning_days,
url=settings.IDTRACKER_BASE_URL + group.about_url(),
))
),
cc=cc,
)
def groups_needing_milestones_due_reminder(early_warning_days):
"""Return groups having milestones that are either
@ -129,7 +131,7 @@ def groups_needing_milestones_due_reminder(early_warning_days):
return Group.objects.filter(state="active", groupmilestone__due__in=[today, today + datetime.timedelta(days=early_warning_days)], groupmilestone__resolved="", groupmilestone__state="active").distinct()
def email_milestones_overdue(group):
to = gather_address_list('milestones_overdue',group=group)
(to, cc) = gather_address_lists('milestones_overdue',group=group)
today = datetime.date.today()
@ -145,7 +147,9 @@ def email_milestones_overdue(group):
dict(group=group,
milestones=milestones,
url=settings.IDTRACKER_BASE_URL + group.about_url(),
))
),
cc=cc,
)
def groups_needing_milestones_overdue_reminder(grace_period=30):
cut_off = datetime.date.today() - datetime.timedelta(days=grace_period)

View file

@ -15,7 +15,7 @@ from ietf.message.models import Message
from ietf.utils.test_utils import TestCase, login_testing_unauthorized
from ietf.utils.test_data import make_test_data
from ietf.utils.mail import outbox, empty_outbox
from ietf.mailtoken.utils import gather_addresses
from ietf.mailtoken.utils import gather_address_lists
class IprTests(TestCase):
@ -537,11 +537,13 @@ I would like to revoke this declaration.
self.assertTrue('joe@test.com' in outbox[0]['To'])
# test process response uninteresting message
addrs = gather_address_lists('ipr_disclosure_submitted').as_strings()
message_string = """To: {}
Cc: {}
From: joe@test.com
Date: {}
Subject: test
""".format(gather_addresses('ipr_disclosure_submitted'),datetime.datetime.now().ctime())
""".format(addrs.to, addrs.cc, datetime.datetime.now().ctime())
result = process_response_email(message_string)
self.assertIsNone(result)

View file

@ -34,7 +34,7 @@ from ietf.person.models import Person
from ietf.secr.utils.document import get_rfc_num, is_draft
from ietf.utils.draft_search import normalize_draftname
from ietf.utils.mail import send_mail, send_mail_message
from ietf.mailtoken.utils import gather_address_list, gather_addresses
from ietf.mailtoken.utils import gather_address_lists
# ----------------------------------------------------------------
# Globals
@ -79,8 +79,7 @@ def get_document_emails(ipr):
else:
cc_list = get_wg_email_list(doc.group)
to_list = gather_addresses('ipr_posted_on_doc',doc=doc)
cc_list = gather_addresses('ipr_posted_on_doc_cc',doc=doc)
(to_list,cc_list) = gather_address_lists('ipr_posted_on_doc',doc=doc)
author_names = ', '.join([a.person.name for a in authors])
context = dict(
@ -99,10 +98,11 @@ def get_posted_emails(ipr):
the notify view when a new disclosure is posted"""
messages = []
addrs = gather_address_lists('ipr_posting_confirmation',ipr=ipr).as_strings(compact=False)
context = dict(
to_email=gather_addresses('ipr_posting_confirmation',ipr=ipr),
to_email=addrs.to,
to_name=ipr.submitter_name,
cc_email=gather_addresses('ipr_posting_confirmation_cc',ipr=ipr),
cc_email=addrs.cc,
ipr=ipr)
text = render_to_string('ipr/posted_submitter_email.txt',context)
messages.append(text)
@ -375,9 +375,10 @@ def email(request, id):
else:
reply_to = get_reply_to()
addrs = gather_address_lists('ipr_disclosure_followup',ipr=ipr).as_strings(compact=False)
initial = {
'to': gather_addresses('ipr_disclosure_followup',ipr=ipr),
'cc': gather_addresses('ipr_disclosure_followup_cc',ipr=ipr),
'to': addrs.to,
'cc': addrs.cc,
'frm': settings.IPR_EMAIL_FROM,
'subject': 'Regarding {}'.format(ipr.title),
'reply_to': reply_to,
@ -473,11 +474,12 @@ def new(request, type, updates=None):
desc="Disclosure Submitted")
# send email notification
to = gather_address_list('ipr_disclosure_submitted')
(to, cc) = gather_address_lists('ipr_disclosure_submitted')
send_mail(request, to, ('IPR Submitter App', 'ietf-ipr@ietf.org'),
'New IPR Submission Notification',
"ipr/new_update_email.txt",
{"ipr": disclosure,})
{"ipr": disclosure,},
cc=cc)
return render(request, "ipr/submitted.html")

View file

@ -7,13 +7,12 @@ from django.core.urlresolvers import reverse as urlreverse
from ietf.utils.mail import send_mail_text
from ietf.liaisons.utils import role_persons_with_fixed_email
from ietf.group.models import Role
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
def send_liaison_by_email(request, liaison):
subject = u'New Liaison Statement, "%s"' % (liaison.title)
from_email = settings.LIAISON_UNIVERSAL_FROM
to_email = gather_address_list('liaison_statement_posted',liaison=liaison)
cc = gather_address_list('liaison_statement_posted_cc',liaison=liaison)
(to_email, cc) = gather_address_lists('liaison_statement_posted',liaison=liaison)
bcc = ['statements@ietf.org']
body = render_to_string('liaisons/liaison_mail.txt', dict(
liaison=liaison,
@ -39,14 +38,13 @@ def notify_pending_by_email(request, liaison):
# to_email.append('%s <%s>' % person.email())
subject = u'New Liaison Statement, "%s" needs your approval' % (liaison.title)
from_email = settings.LIAISON_UNIVERSAL_FROM
to = gather_address_list('liaison_approval_requested',liaison=liaison)
(to, cc) = gather_address_lists('liaison_approval_requested',liaison=liaison)
body = render_to_string('liaisons/pending_liaison_mail.txt', dict(
liaison=liaison,
url=settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk)),
referenced_url=settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.related_to.pk)) if liaison.related_to else None,
))
# send_mail_text(request, to_email, from_email, subject, body)
send_mail_text(request, to, from_email, subject, body)
send_mail_text(request, to, from_email, subject, body, cc=cc)
def send_sdo_reminder(sdo):
roles = Role.objects.filter(name="liaiman", group=sdo)
@ -56,7 +54,7 @@ def send_sdo_reminder(sdo):
manager_role = roles[0]
subject = 'Request for update of list of authorized individuals'
to_email = gather_address_list('liaison_manager_update_request',group=sdo)
(to_email,cc) = gather_address_lists('liaison_manager_update_request',group=sdo)
name = manager_role.person.plain_name()
authorized_list = role_persons_with_fixed_email(sdo, "auth")
@ -66,7 +64,7 @@ def send_sdo_reminder(sdo):
individuals=authorized_list,
))
send_mail_text(None, to_email, settings.LIAISON_UNIVERSAL_FROM, subject, body)
send_mail_text(None, to_email, settings.LIAISON_UNIVERSAL_FROM, subject, body, cc=cc)
return body
@ -93,8 +91,7 @@ def possibly_send_deadline_reminder(liaison):
days_msg = 'expires %s' % PREVIOUS_DAYS[days_to_go]
from_email = settings.LIAISON_UNIVERSAL_FROM
to_email = gather_address_list('liaison_deadline_soon',liaison=liaison)
cc = gather_address_list('liaison_deadline_soon_cc',liaison=liaison)
(to_email, cc) = gather_address_lists('liaison_deadline_soon',liaison=liaison)
bcc = 'statements@ietf.org'
body = render_to_string('liaisons/liaison_deadline_mail.txt',
dict(liaison=liaison,

View file

@ -79,7 +79,7 @@ def make_recipients(apps):
rc(slug='conflict_review_stream_manager',
desc="The stream manager of a document being reviewed for IETF stream conflicts",
template = None )
template=None )
rc(slug='conflict_review_steering_group',
desc="The steering group (e.g. IRSG) of a document being reviewed for IETF stream conflicts",
@ -165,6 +165,10 @@ def make_recipients(apps):
desc="The session request ticketing system",
template='<session-request@ietf.org>')
rc(slug='session_requester',
desc="The person that requested a meeting slot for a given group",
template=None)
rc(slug='logged_in_person',
desc="The person currently logged into the datatracker who initiated a given action",
template='{% if person and person.email_address %}<{{ person.email_address }}>{% endif %}')
@ -241,6 +245,17 @@ def make_mailtokens(apps):
MailToken=apps.get_model('mailtoken','MailToken')
def mt_factory(slug,desc,to_slugs,cc_slugs=[]):
# Try to protect ourselves from typos
all_slugs = to_slugs[:]
all_slugs.extend(cc_slugs)
for recipient_slug in all_slugs:
try:
Recipient.objects.get(slug=recipient_slug)
except Recipient.DoesNotExist:
print "****Some rule tried to use",recipient_slug
raise
m = MailToken.objects.create(slug=slug, desc=desc)
m.to = Recipient.objects.filter(slug__in=to_slugs)
m.cc = Recipient.objects.filter(slug__in=cc_slugs)
@ -325,7 +340,7 @@ def make_mailtokens(apps):
cc_slugs=['iesg',
'rfc_editor',
'doc_notify',
'doc_affectddoc_authors',
'doc_affecteddoc_authors',
'doc_affecteddoc_group_chairs',
'doc_affecteddoc_notify',
],
@ -347,7 +362,7 @@ def make_mailtokens(apps):
'doc_shepherd',
'doc_authors',
'doc_notify',
'doc_group_list_email',
'doc_group_mail_list',
'doc_group_chairs',
'doc_affecteddoc_authors',
'doc_affecteddoc_group_chairs',
@ -577,7 +592,7 @@ def make_mailtokens(apps):
desc="Recipients for notification of a new version of an existing document",
to_slugs=['doc_notify',
'doc_ad',
'non_ietf_stream_manager',
'doc_non_ietf_stream_manager',
'rfc_editor_if_doc_in_queue',
'doc_discussing_ads',
])
@ -744,6 +759,16 @@ def make_mailtokens(apps):
"completed questionairre response",
to_slugs=['nominee', ])
mt_factory(slug='doc_replacement_suggested',
desc="Recipients for suggestions that this doc replaces or is replace by "
"some other document",
to_slugs=['doc_group_chairs',
'doc_group_responsible_directors',
'doc_non_ietf_stream_manager',
'iesg_secretary',
])
def forward(apps, schema_editor):
make_recipients(apps)

View file

@ -252,3 +252,10 @@ class Recipient(models.Model):
group=kwargs['group']
addrs.extend(group.role_set.filter(name='liaiman').values_list('email__address',flat=True))
return addrs
def gather_session_requester(self, **kwargs):
addrs=[]
if 'session' in kwargs:
session = kwargs['session']
addrs.append(session.requested_by.role_email('chair').address)
return addrs

View file

@ -1,22 +1,32 @@
from collections import namedtuple
from ietf.mailtoken.models import MailToken, Recipient
def gather_address_list(slug,**kwargs):
addrs = []
class AddrLists(namedtuple('AddrLists',['to','cc'])):
if slug.endswith('_cc'):
mailtoken = MailToken.objects.get(slug=slug[:-3])
for recipient in mailtoken.cc.all():
addrs.extend(recipient.gather(**kwargs))
else:
mailtoken = MailToken.objects.get(slug=slug)
for recipient in mailtoken.to.all():
addrs.extend(recipient.gather(**kwargs))
__slots__ = ()
return list(set([addr for addr in addrs if addr]))
def as_strings(self,compact=True):
def gather_addresses(slug,**kwargs):
return ",\n ".join(gather_address_list(slug,**kwargs))
separator = ", " if compact else ",\n "
to_string = separator.join(self.to)
cc_string = separator.join(self.cc)
return namedtuple('AddrListsAsStrings',['to','cc'])(to=to_string,cc=cc_string)
def gather_address_lists(slug, **kwargs):
mailtoken = MailToken.objects.get(slug=slug)
to = set()
for recipient in mailtoken.to.all():
to.update(recipient.gather(**kwargs))
to.discard('')
cc = set()
for recipient in mailtoken.cc.all():
cc.update(recipient.gather(**kwargs))
cc.discard('')
return AddrLists(to=list(to),cc=list(cc))
def get_base_ipr_request_address():
return Recipient.objects.get(slug='ipr_requests').gather()[0]

View file

@ -4719,6 +4719,14 @@
"model": "mailtoken.recipient",
"pk": "rfc_editor_if_doc_in_queue"
},
{
"fields": {
"template": null,
"desc": "The person that requested a meeting slot for a given group"
},
"model": "mailtoken.recipient",
"pk": "session_requester"
},
{
"fields": {
"template": "<session-request@ietf.org>",
@ -4845,6 +4853,7 @@
{
"fields": {
"cc": [
"doc_affecteddoc_authors",
"doc_affecteddoc_group_chairs",
"doc_affecteddoc_notify",
"doc_notify",
@ -5034,6 +5043,20 @@
"model": "mailtoken.mailtoken",
"pk": "doc_replacement_changed"
},
{
"fields": {
"cc": [],
"to": [
"doc_group_chairs",
"doc_group_responsible_directors",
"doc_non_ietf_stream_manager",
"iesg_secretary"
],
"desc": "Recipients for suggestions that this doc replaces or is replace by some other document"
},
"model": "mailtoken.mailtoken",
"pk": "doc_replacement_suggested"
},
{
"fields": {
"cc": [],
@ -5220,6 +5243,7 @@
"doc_affecteddoc_notify",
"doc_authors",
"doc_group_chairs",
"doc_group_mail_list",
"doc_notify",
"doc_shepherd"
],
@ -5564,7 +5588,8 @@
"group_responsible_directors"
],
"to": [
"group_chairs"
"group_chairs",
"session_requester"
],
"desc": "Recipients for details when a session has been scheduled"
},
@ -5650,6 +5675,7 @@
"to": [
"doc_ad",
"doc_discussing_ads",
"doc_non_ietf_stream_manager",
"doc_notify",
"rfc_editor_if_doc_in_queue"
],

View file

@ -20,7 +20,7 @@ from ietf.person.models import Email
from ietf.person.fields import SearchableEmailField
from ietf.utils.fields import MultiEmailField
from ietf.utils.mail import send_mail
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
ROLODEX_URL = getattr(settings, 'ROLODEX_URL', None)
@ -408,12 +408,12 @@ class NominateForm(BaseNomcomForm, forms.ModelForm):
if author:
subject = 'Nomination receipt'
from_email = settings.NOMCOM_FROM_EMAIL
to_email = gather_address_list('nomination_receipt_requested',nominator=author.address)
(to_email, cc) = gather_address_lists('nomination_receipt_requested',nominator=author.address)
context = {'nominee': nominee.email.person.name,
'comments': comments,
'position': position.name}
path = nomcom_template_path + NOMINATION_RECEIPT_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context)
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
return nomination
@ -526,12 +526,12 @@ class FeedbackForm(BaseNomcomForm, forms.ModelForm):
if author:
subject = "NomCom comment confirmation"
from_email = settings.NOMCOM_FROM_EMAIL
to_email = gather_address_list('nomcom_comment_receipt_requested',commenter=author.address)
(to_email, cc) = gather_address_lists('nomcom_comment_receipt_requested',commenter=author.address)
context = {'nominee': self.nominee.email.person.name,
'comments': comments,
'position': self.position.name}
path = nomcom_template_path + FEEDBACK_RECEIPT_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context)
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
class Meta:
model = Feedback

View file

@ -18,7 +18,7 @@ from django.utils.encoding import smart_str
from ietf.dbtemplate.models import DBTemplate
from ietf.person.models import Email, Person
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
from ietf.utils.pipe import pipe
from ietf.utils import unaccent
from ietf.utils.mail import send_mail_text, send_mail
@ -208,7 +208,7 @@ def send_accept_reminder_to_nominee(nominee_position):
nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym
mail_path = nomcom_template_path + NOMINEE_ACCEPT_REMINDER_TEMPLATE
nominee = nominee_position.nominee
to_email = gather_address_list('nomination_accept_reminder',nominee=nominee.email.address)
(to_email, cc) = gather_address_lists('nomination_accept_reminder',nominee=nominee.email.address)
hash = get_hash_nominee_position(today, nominee_position.id)
accept_url = reverse('nomcom_process_nomination_status',
@ -234,7 +234,7 @@ def send_accept_reminder_to_nominee(nominee_position):
body = render_to_string(mail_path, context)
path = '%s%d/%s' % (nomcom_template_path, position.id, QUESTIONNAIRE_TEMPLATE)
body += '\n\n%s' % render_to_string(path, context)
send_mail_text(None, to_email, from_email, subject, body)
send_mail_text(None, to_email, from_email, subject, body, cc=cc)
def send_questionnaire_reminder_to_nominee(nominee_position):
subject = 'Reminder: please complete the Nomcom questionnaires for your nomination.'
@ -245,7 +245,7 @@ def send_questionnaire_reminder_to_nominee(nominee_position):
nomcom_template_path = '/nomcom/%s/' % nomcom.group.acronym
mail_path = nomcom_template_path + NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE
nominee = nominee_position.nominee
to_email = gather_address_list('nomcom_questionnaire_reminder',nominee=nominee.email.address)
(to_email,cc) = gather_address_lists('nomcom_questionnaire_reminder',nominee=nominee.email.address)
context = {'nominee': nominee,
'position': position,
@ -254,7 +254,7 @@ def send_questionnaire_reminder_to_nominee(nominee_position):
body = render_to_string(mail_path, context)
path = '%s%d/%s' % (nomcom_template_path, position.id, QUESTIONNAIRE_TEMPLATE)
body += '\n\n%s' % render_to_string(path, context)
send_mail_text(None, to_email, from_email, subject, body)
send_mail_text(None, to_email, from_email, subject, body, cc=cc)
def send_reminder_to_nominees(nominees,type):
addrs = []
@ -295,18 +295,18 @@ def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, aut
# send email to secretariat and nomcomchair to warn about the new person
subject = 'New person is created'
from_email = settings.NOMCOM_FROM_EMAIL
to_email = gather_address_list('nomination_created_person',nomcom=nomcom)
(to_email, cc) = gather_address_lists('nomination_created_person',nomcom=nomcom)
context = {'email': email.address,
'fullname': email.person.name,
'person_id': email.person.id}
path = nomcom_template_path + INEXISTENT_PERSON_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context)
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
if nominee_position_created:
# send email to nominee
subject = 'IETF Nomination Information'
from_email = settings.NOMCOM_FROM_EMAIL
to_email = gather_address_list('nomination_new_nominee',nominee=email.address)
(to_email, cc) = gather_address_lists('nomination_new_nominee',nominee=email.address)
domain = Site.objects.get_current().domain
today = datetime.date.today().strftime('%Y%m%d')
hash = get_hash_nominee_position(today, nominee_position.id)
@ -332,13 +332,13 @@ def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, aut
'decline_url': decline_url}
path = nomcom_template_path + NOMINEE_EMAIL_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context)
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
# send email to nominee with questionnaire
if nomcom.send_questionnaire:
subject = '%s Questionnaire' % position
from_email = settings.NOMCOM_FROM_EMAIL
to_email = gather_address_list('nomcom_questionnaire',nominee=email.address)
(to_email, cc) = gather_address_lists('nomcom_questionnaire',nominee=email.address)
context = {'nominee': email.person.name,
'position': position.name}
path = '%s%d/%s' % (nomcom_template_path,
@ -347,12 +347,12 @@ def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, aut
path = '%s%d/%s' % (nomcom_template_path,
position.id, QUESTIONNAIRE_TEMPLATE)
body += '\n\n%s' % render_to_string(path, context)
send_mail_text(None, to_email, from_email, subject, body)
send_mail_text(None, to_email, from_email, subject, body, cc=cc)
# send emails to nomcom chair
subject = 'Nomination Information'
from_email = settings.NOMCOM_FROM_EMAIL
to_email = gather_address_list('nomination_received',nomcom=nomcom)
(to_email, cc) = gather_address_lists('nomination_received',nomcom=nomcom)
context = {'nominee': email.person.name,
'nominee_email': email.address,
'position': position.name}
@ -365,7 +365,7 @@ def get_or_create_nominee(nomcom, candidate_name, candidate_email, position, aut
'nominator_email': ''})
path = nomcom_template_path + NOMINATION_EMAIL_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context)
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
return nominee

View file

@ -26,7 +26,7 @@ from ietf.secr.proceedings.views import build_choices, handle_upload_file, make_
from ietf.secr.sreq.forms import GroupSelectForm
from ietf.secr.sreq.views import get_initial_session
from ietf.secr.utils.meeting import get_session, get_timeslot
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
# prep for agenda changes
@ -188,8 +188,7 @@ def send_notifications(meeting, groups, person):
now = datetime.datetime.now()
for group in groups:
sessions = group.session_set.filter(meeting=meeting)
to_email = gather_address_list('session_scheduled',group=group,person=sessions[0].requested_by)
cc_list = gather_address_list('session_scheduled_cc',group=group,person=sessions[0].requested_by)
addrs = gather_address_lists('session_scheduled',group=group,session=sessions[0])
from_email = ('"IETF Secretariat"','agenda@ietf.org')
if len(sessions) == 1:
subject = '%s - Requested session has been scheduled for IETF %s' % (group.acronym, meeting.number)
@ -222,12 +221,12 @@ def send_notifications(meeting, groups, person):
context['login'] = sessions[0].requested_by
send_mail(None,
to_email,
addrs.to,
from_email,
subject,
template,
context,
cc=cc_list)
cc=addrs.cc)
# create sent_notification event
GroupEvent.objects.create(group=group,time=now,type='sent_notification',

View file

@ -16,7 +16,7 @@ from ietf.secr.utils.decorators import check_permissions
from ietf.secr.utils.group import groups_by_session
from ietf.utils.mail import send_mail
from ietf.person.models import Person
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
# -------------------------------------------------
# Globals
@ -113,8 +113,7 @@ def send_notification(group,meeting,login,session,action):
session argument is a dictionary of fields from the session request form
action argument is a string [new|update].
'''
to_email = gather_address_list('session_requested',group=group,person=login)
cc_list = gather_address_list('session_requested_cc',group=group,person=login)
(to_email, cc_list) = gather_address_lists('session_requested',group=group,person=login)
from_email = ('"IETF Meeting Session Request Tool"','session_request_developers@ietf.org')
subject = '%s - New Meeting Session Request for IETF %s' % (group.acronym, meeting.number)
template = 'sreq/session_request_notification.txt'
@ -137,8 +136,7 @@ def send_notification(group,meeting,login,session,action):
# change headers TO=ADs, CC=session-request, submitter and cochairs
if session.get('length_session3',None):
context['session']['num_session'] = 3
to_email = gather_address_list('session_requested_long',group=group,person=login)
cc_list = gather_address_list('session_requested_long_cc',group=group,person=login)
(to_email, cc_list) = gather_address_lists('session_requested_long',group=group,person=login)
subject = '%s - Request for meeting session approval for IETF %s' % (group.acronym, meeting.number)
template = 'sreq/session_approval_notification.txt'
#status_text = 'the %s Directors for approval' % group.parent
@ -209,8 +207,7 @@ def cancel(request, acronym):
session.scheduledsession_set.all().delete()
# send notifitcation
to_email = gather_address_list('session_request_cancelled',group=group,person=login)
cc_list = gather_address_list('session_request_cancelled_cc',group=group,person=login)
(to_email, cc_list) = gather_address_lists('session_request_cancelled',group=group,person=login)
from_email = ('"IETF Meeting Session Request Tool"','session_request_developers@ietf.org')
subject = '%s - Cancelling a meeting request for IETF %s' % (group.acronym, meeting.number)
send_mail(request, to_email, from_email, subject, 'sreq/session_cancel_notification.txt',
@ -626,8 +623,7 @@ def no_session(request, acronym):
session_save(session)
# send notification
to_email = gather_address_list('session_request_not_meeting',group=group,person=login)
cc_list = gather_address_list('session_request_not_meeting_cc',group=group,person=login)
(to_email, cc_list) = gather_address_lists('session_request_not_meeting',group=group,person=login)
from_email = ('"IETF Meeting Session Request Tool"','session_request_developers@ietf.org')
subject = '%s - Not having a session at IETF %s' % (group.acronym, meeting.number)
send_mail(request, to_email, from_email, subject, 'sreq/not_meeting_notification.txt',

View file

@ -8,56 +8,66 @@ from ietf.doc.models import Document
from ietf.person.models import Person
from ietf.message.models import Message
from ietf.utils.accesstoken import generate_access_token
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
def send_submission_confirmation(request, submission):
subject = 'Confirm submission of I-D %s' % submission.name
from_email = settings.IDSUBMIT_FROM_EMAIL
to_email = gather_address_list('sub_confirmation_requested',submission=submission)
(to_email, cc) = gather_address_lists('sub_confirmation_requested',submission=submission)
confirm_url = settings.IDTRACKER_BASE_URL + urlreverse('submit_confirm_submission', kwargs=dict(submission_id=submission.pk, auth_token=generate_access_token(submission.auth_key)))
status_url = settings.IDTRACKER_BASE_URL + urlreverse('submit_submission_status_by_hash', kwargs=dict(submission_id=submission.pk, access_token=submission.access_token()))
send_mail(request, to_email, from_email, subject, 'submit/confirm_submission.txt', {
'submission': submission,
'confirm_url': confirm_url,
'status_url': status_url,
})
send_mail(request, to_email, from_email, subject, 'submit/confirm_submission.txt',
{
'submission': submission,
'confirm_url': confirm_url,
'status_url': status_url,
},
cc=cc)
return to_email
all_addrs = to_email
all_addrs.extend(cc)
return all_addrs
def send_full_url(request, submission):
subject = 'Full URL for managing submission of draft %s' % submission.name
from_email = settings.IDSUBMIT_FROM_EMAIL
to_email = gather_address_list('sub_management_url_requested',submission=submission)
(to_email, cc) = gather_address_lists('sub_management_url_requested',submission=submission)
url = settings.IDTRACKER_BASE_URL + urlreverse('submit_submission_status_by_hash', kwargs=dict(submission_id=submission.pk, access_token=submission.access_token()))
send_mail(request, to_email, from_email, subject, 'submit/full_url.txt', {
'submission': submission,
'url': url,
})
send_mail(request, to_email, from_email, subject, 'submit/full_url.txt',
{
'submission': submission,
'url': url,
},
cc=cc)
return to_email
all_addrs = to_email
all_addrs.extend(cc)
return all_addrs
def send_approval_request_to_group(request, submission):
subject = 'New draft waiting for approval: %s' % submission.name
from_email = settings.IDSUBMIT_FROM_EMAIL
to_email = gather_address_list('sub_chair_approval_requested',submission=submission)
(to_email,cc) = gather_address_lists('sub_chair_approval_requested',submission=submission)
if not to_email:
return to_email
send_mail(request, to_email, from_email, subject, 'submit/approval_request.txt', {
'submission': submission,
'domain': Site.objects.get_current().domain,
})
return to_email
send_mail(request, to_email, from_email, subject, 'submit/approval_request.txt',
{
'submission': submission,
'domain': Site.objects.get_current().domain,
},
cc=cc)
all_addrs = to_email
all_addrs.extend(cc)
return all_addrs
def send_manual_post_request(request, submission, errors):
subject = u'Manual Post Requested for %s' % submission.name
from_email = settings.IDSUBMIT_FROM_EMAIL
to_email = gather_address_list('sub_manual_post_requested',submission=submission)
cc = gather_address_list('sub_manual_post_requested_cc',submission=submission)
(to_email,cc) = gather_address_lists('sub_manual_post_requested',submission=submission)
send_mail(request, to_email, from_email, subject, 'submit/manual_post_request.txt', {
'submission': submission,
'url': settings.IDTRACKER_BASE_URL + urlreverse('submit_submission_status', kwargs=dict(submission_id=submission.pk)),
@ -75,8 +85,7 @@ def announce_to_lists(request, submission):
pass
m.subject = 'I-D Action: %s-%s.txt' % (submission.name, submission.rev)
m.frm = settings.IDSUBMIT_ANNOUNCE_FROM_EMAIL
m.to = gather_address_list('sub_announced',submission=submission)
m.cc = gather_address_list('sub_announced_cc',submission=submission)
(m.to, m.cc) = gather_address_lists('sub_announced',submission=submission)
m.body = render_to_string('submit/announce_to_lists.txt',
dict(submission=submission,
settings=settings))
@ -87,17 +96,18 @@ def announce_to_lists(request, submission):
def announce_new_version(request, submission, draft, state_change_msg):
to_email = gather_address_list('sub_new_version',doc=draft,submission=submission)
(to_email,cc) = gather_address_lists('sub_new_version',doc=draft,submission=submission)
if to_email:
subject = 'New Version Notification - %s-%s.txt' % (submission.name, submission.rev)
from_email = settings.IDSUBMIT_ANNOUNCE_FROM_EMAIL
send_mail(request, to_email, from_email, subject, 'submit/announce_new_version.txt',
{'submission': submission,
'msg': state_change_msg})
'msg': state_change_msg},
cc=cc)
def announce_to_authors(request, submission):
to_email = gather_address_list('sub_announced_to_authors',submission=submission)
(to_email, cc) = gather_address_lists('sub_announced_to_authors',submission=submission)
from_email = settings.IDSUBMIT_ANNOUNCE_FROM_EMAIL
subject = 'New Version Notification for %s-%s.txt' % (submission.name, submission.rev)
if submission.group:
@ -108,4 +118,5 @@ def announce_to_authors(request, submission):
group = 'Individual Submission'
send_mail(request, to_email, from_email, subject, 'submit/announce_to_authors.txt',
{'submission': submission,
'group': group})
'group': group},
cc=cc)

View file

@ -221,8 +221,8 @@ class SubmitTests(TestCase):
self.assertTrue("review" in outbox[-1]["Subject"].lower())
self.assertTrue(name in unicode(outbox[-1]))
self.assertTrue(sug_replaced_alias.name in unicode(outbox[-1]))
self.assertTrue("ameschairman" in outbox[-1]["To"].lower())
self.assertTrue("marschairman" in outbox[-1]["To"].lower())
self.assertTrue("ames-chairs@" in outbox[-1]["To"].lower())
self.assertTrue("mars-chairs@" in outbox[-1]["To"].lower())
def test_submit_new_wg_txt(self):
self.submit_new_wg(["txt"])

View file

@ -23,7 +23,7 @@ from ietf.submit.utils import check_idnits, found_idnits, validate_submission, c
from ietf.submit.utils import post_submission, cancel_submission, rename_submission_files
from ietf.utils.accesstoken import generate_random_key, generate_access_token
from ietf.utils.draft import Draft
from ietf.mailtoken.utils import gather_address_list
from ietf.mailtoken.utils import gather_address_lists
def upload_submission(request):
@ -181,7 +181,9 @@ def submission_status(request, submission_id, access_token=None):
can_force_post = is_secretariat and submission.state.next_states.filter(slug="posted")
show_send_full_url = not key_matched and not is_secretariat and submission.state_id not in ("cancel", "posted")
confirmation_list = gather_address_list('sub_confirmation_requested',submission=submission)
addrs = gather_address_lists('sub_confirmation_requested',submission=submission)
confirmation_list = addrs.to
confirmation_list.extend(addrs.cc)
requires_group_approval = (submission.rev == '00' and submission.group and submission.group.type_id in ("wg", "rg", "ietf", "irtf", "iab", "iana", "rfcedtyp") and not Preapproval.objects.filter(name=submission.name).exists())