in the AD edit form, change search to define area = doc.group or doc.group.parent (so don't take AD into account), plus a bunch of small tweaks to make a document with an area set as group behave like an individually submitted document, at least for the time being (they are presented as "Individual in xyz area" on their document page) - Legacy-Id: 3968
675 lines
28 KiB
Python
675 lines
28 KiB
Python
# generation of mails
|
|
|
|
import textwrap
|
|
from datetime import datetime, date, time, timedelta
|
|
|
|
from django.template.loader import render_to_string
|
|
from django.utils.html import strip_tags
|
|
from django.conf import settings
|
|
from django.core.urlresolvers import reverse as urlreverse
|
|
|
|
from ietf.utils.mail import send_mail, send_mail_text
|
|
from ietf.idtracker.models import *
|
|
from ietf.ipr.search import iprs_from_docs
|
|
from ietf.ietfworkflows.streams import (get_stream_from_draft)
|
|
from ietf.ietfworkflows.models import (Stream)
|
|
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias
|
|
from ietf.person.models import Person
|
|
from ietf.group.models import Group
|
|
|
|
def email_state_changed(request, doc, text):
|
|
to = [x.strip() for x in doc.idinternal.state_change_notice_to.replace(';', ',').split(',')]
|
|
if to:
|
|
send_mail(request, to, None,
|
|
"ID Tracker State Update Notice: %s" % doc.file_tag(),
|
|
"idrfc/state_changed_email.txt",
|
|
dict(text=text,
|
|
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
|
|
|
def email_state_changedREDESIGN(request, doc, text):
|
|
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
|
|
if not to:
|
|
return
|
|
|
|
text = strip_tags(text)
|
|
send_mail(request, to, None,
|
|
"ID Tracker State Update Notice: %s" % doc.file_tag(),
|
|
"idrfc/state_changed_email.txt",
|
|
dict(text=text,
|
|
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
email_state_changed = email_state_changedREDESIGN
|
|
|
|
def html_to_text(html):
|
|
return strip_tags(html.replace("<", "<").replace(">", ">").replace("&", "&").replace("<br>", "\n"))
|
|
|
|
def email_owner(request, doc, owner, changed_by, text, subject=None):
|
|
if not owner or not changed_by or owner == changed_by:
|
|
return
|
|
|
|
to = u"%s <%s>" % owner.person.email()
|
|
send_mail(request, to,
|
|
"DraftTracker Mail System <iesg-secretary@ietf.org>",
|
|
"%s updated by %s" % (doc.file_tag(), changed_by),
|
|
"idrfc/change_notice.txt",
|
|
dict(text=html_to_text(text),
|
|
doc=doc,
|
|
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
|
|
|
def email_adREDESIGN(request, doc, ad, changed_by, text, subject=None):
|
|
if not ad or not changed_by or ad == changed_by:
|
|
return
|
|
|
|
to = ad.role_email("ad").formatted_email()
|
|
send_mail(request, to,
|
|
"DraftTracker Mail System <iesg-secretary@ietf.org>",
|
|
"%s updated by %s" % (doc.file_tag(), changed_by.plain_name()),
|
|
"idrfc/change_notice.txt",
|
|
dict(text=html_to_text(text),
|
|
doc=doc,
|
|
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
email_owner = email_adREDESIGN
|
|
|
|
|
|
def full_intended_status(intended_status):
|
|
s = str(intended_status)
|
|
# FIXME: this should perhaps be defined in the db
|
|
if "Informational" in s:
|
|
return "an Informational RFC"
|
|
elif "Experimental" in s:
|
|
return "an Experimental RFC"
|
|
elif "Proposed" in s:
|
|
return "a Proposed Standard"
|
|
elif "Draft" in s:
|
|
return "a Draft Standard"
|
|
elif "BCP" in s:
|
|
return "a BCP"
|
|
elif "Standard" in s:
|
|
return "a Full Standard"
|
|
elif "Request" in s or "None" in s:
|
|
return "*** YOU MUST SELECT AN INTENDED STATUS FOR THIS DRAFT AND REGENERATE THIS TEXT ***"
|
|
else:
|
|
return "a %s" % s
|
|
|
|
def generate_ballot_writeup(request, doc):
|
|
e = WriteupDocEvent()
|
|
e.type = "changed_ballot_writeup_text"
|
|
e.by = request.user.get_profile()
|
|
e.doc = doc
|
|
e.desc = u"Ballot writeup was generated"
|
|
e.text = unicode(render_to_string("idrfc/ballot_writeup.txt"))
|
|
e.save()
|
|
|
|
return e
|
|
|
|
def generate_last_call_announcement(request, doc):
|
|
status = full_intended_status(doc.intended_status).replace("a ", "").replace("an ", "")
|
|
|
|
expiration_date = date.today() + timedelta(days=14)
|
|
cc = []
|
|
if doc.group.acronym_id == Acronym.INDIVIDUAL_SUBMITTER:
|
|
group = "an individual submitter"
|
|
expiration_date += timedelta(days=14)
|
|
else:
|
|
group = "the %s WG (%s)" % (doc.group.name, doc.group.acronym)
|
|
cc.append(doc.group.ietfwg.email_address)
|
|
|
|
urls = []
|
|
docs = [d.document() for d in doc.idinternal.ballot_set()]
|
|
for d in docs:
|
|
d.full_status = full_intended_status(d.intended_status)
|
|
d.filled_title = textwrap.fill(d.title, width=70, subsequent_indent=" " * 3)
|
|
urls.append(settings.IDTRACKER_BASE_URL + d.idinternal.get_absolute_url())
|
|
|
|
iprs, docs = iprs_from_docs(docs)
|
|
if iprs:
|
|
ipr_links = [ urlreverse("ietf.ipr.views.show", kwargs=dict(ipr_id=i.ipr_id)) for i in iprs]
|
|
ipr_links = [ settings.IDTRACKER_BASE_URL+url if not url.startswith("http") else url for url in ipr_links ]
|
|
else:
|
|
ipr_links = None
|
|
|
|
return render_to_string("idrfc/last_call_announcement.txt",
|
|
dict(doc=doc,
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
|
|
expiration_date=expiration_date.strftime("%Y-%m-%d"), #.strftime("%B %-d, %Y"),
|
|
cc=", ".join("<%s>" % e for e in cc),
|
|
group=group,
|
|
docs=docs,
|
|
urls=urls,
|
|
status=status,
|
|
impl_report="Draft" in status or "Full" in status,
|
|
ipr_links=ipr_links,
|
|
)
|
|
)
|
|
|
|
def generate_last_call_announcementREDESIGN(request, doc):
|
|
doc.full_status = full_intended_status(doc.intended_std_level)
|
|
status = doc.full_status.replace("a ", "").replace("an ", "")
|
|
|
|
expiration_date = date.today() + timedelta(days=14)
|
|
cc = []
|
|
if doc.group.type_id in ("individ", "area"):
|
|
group = "an individual submitter"
|
|
expiration_date += timedelta(days=14)
|
|
else:
|
|
group = "the %s WG (%s)" % (doc.group.name, doc.group.acronym)
|
|
if doc.group.list_email:
|
|
cc.append(doc.group.list_email)
|
|
|
|
doc.filled_title = textwrap.fill(doc.title, width=70, subsequent_indent=" " * 3)
|
|
|
|
iprs, _ = iprs_from_docs([ DocAlias.objects.get(name=doc.canonical_name()) ])
|
|
if iprs:
|
|
ipr_links = [ urlreverse("ietf.ipr.views.show", kwargs=dict(ipr_id=i.ipr_id)) for i in iprs]
|
|
ipr_links = [ settings.IDTRACKER_BASE_URL+url if not url.startswith("http") else url for url in ipr_links ]
|
|
else:
|
|
ipr_links = None
|
|
|
|
mail = render_to_string("idrfc/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"),
|
|
cc=", ".join("<%s>" % e for e in cc),
|
|
group=group,
|
|
docs=[ doc ],
|
|
urls=[ settings.IDTRACKER_BASE_URL + doc.get_absolute_url() ],
|
|
status=status,
|
|
impl_report="Draft" in status or "Full" in status,
|
|
ipr_links=ipr_links,
|
|
)
|
|
)
|
|
|
|
e = WriteupDocEvent()
|
|
e.type = "changed_last_call_text"
|
|
e.by = request.user.get_profile()
|
|
e.doc = doc
|
|
e.desc = u"Last call announcement was generated"
|
|
e.text = unicode(mail)
|
|
e.save()
|
|
|
|
return e
|
|
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
generate_last_call_announcement = generate_last_call_announcementREDESIGN
|
|
|
|
def generate_approval_mail(request, doc):
|
|
if doc.idinternal.cur_state_id in IDState.DO_NOT_PUBLISH_STATES or doc.idinternal.via_rfc_editor:
|
|
return generate_approval_mail_rfc_editor(request, doc)
|
|
|
|
status = full_intended_status(doc.intended_status).replace("a ", "").replace("an ", "")
|
|
if "an " in full_intended_status(doc.intended_status):
|
|
action_type = "Document"
|
|
else:
|
|
action_type = "Protocol"
|
|
|
|
cc = settings.DOC_APPROVAL_EMAIL_CC
|
|
|
|
if doc.group.ietfwg.group_type.type != "AG" and not doc.group.name.endswith("Working Group"):
|
|
doc.group.name_with_wg = doc.group.name + " Working Group"
|
|
cc.append("%s mailing list <%s>" % (doc.group.acronym, doc.group.ietfwg.email_address))
|
|
cc.append("%s chair <%s-chairs@tools.ietf.org>" % (doc.group.acronym, doc.group.acronym))
|
|
else:
|
|
doc.group.name_with_wg = doc.group.name
|
|
|
|
docs = [d.document() for d in doc.idinternal.ballot_set()]
|
|
for d in docs:
|
|
d.full_status = full_intended_status(d.intended_status)
|
|
d.filled_title = textwrap.fill(d.title, width=70, subsequent_indent=" " * 3)
|
|
|
|
if doc.group.acronym_id == Acronym.INDIVIDUAL_SUBMITTER:
|
|
if len(docs) > 1:
|
|
made_by = "These documents have been reviewed in the IETF but are not the products of an IETF Working Group."
|
|
else:
|
|
made_by = "This document has been reviewed in the IETF but is not the product of an IETF Working Group."
|
|
else:
|
|
if len(docs) > 1:
|
|
made_by = "These documents are products of the %s." % doc.group.name_with_wg
|
|
else:
|
|
made_by = "This document is the product of the %s." % doc.group.name_with_wg
|
|
|
|
director = doc.idinternal.job_owner
|
|
other_director = IESGLogin.objects.filter(person__in=[ad.person for ad in doc.group.ietfwg.area_directors()]).exclude(id=doc.idinternal.job_owner_id)
|
|
if doc.group.acronym_id != Acronym.INDIVIDUAL_SUBMITTER and other_director:
|
|
contacts = "The IESG contact persons are %s and %s." % (director, other_director[0])
|
|
else:
|
|
contacts = "The IESG contact person is %s." % director
|
|
|
|
doc_type = "RFC" if type(doc) == Rfc else "Internet Draft"
|
|
|
|
return render_to_string("idrfc/approval_mail.txt",
|
|
dict(doc=doc,
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
|
|
cc=",\n ".join(cc),
|
|
docs=docs,
|
|
doc_type=doc_type,
|
|
made_by=made_by,
|
|
contacts=contacts,
|
|
status=status,
|
|
action_type=action_type,
|
|
)
|
|
)
|
|
|
|
def generate_approval_mail_rfc_editor(request, doc):
|
|
full_status = full_intended_status(doc.intended_status)
|
|
status = full_status.replace("a ", "").replace("an ", "")
|
|
disapproved = doc.idinternal.cur_state_id in IDState.DO_NOT_PUBLISH_STATES
|
|
doc_type = "RFC" if type(doc) == Rfc else "Internet Draft"
|
|
|
|
stream = get_stream_from_draft(doc)
|
|
to = ", ".join([u"%s <%s>" % x.email() for x in stream.get_chairs_for_document(doc) ])
|
|
if stream.name == "IRTF":
|
|
# also send to the IRSG
|
|
to += ", Internet Research Steering Group (IRSG) <irsg@irtf.org>"
|
|
|
|
return render_to_string("idrfc/approval_mail_rfc_editor.txt",
|
|
dict(doc=doc,
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
|
|
doc_type=doc_type,
|
|
status=status,
|
|
full_status=full_status,
|
|
disapproved=disapproved,
|
|
to=to,
|
|
)
|
|
)
|
|
|
|
DO_NOT_PUBLISH_IESG_STATES = ("nopubadw", "nopubanw")
|
|
|
|
def generate_approval_mailREDESIGN(request, doc):
|
|
if doc.get_state_slug("draft-iesg") in DO_NOT_PUBLISH_IESG_STATES or doc.tags.filter(slug='via-rfc'):
|
|
mail = generate_approval_mail_rfc_editor(request, doc)
|
|
else:
|
|
mail = generate_approval_mail_approved(request, doc)
|
|
|
|
e = WriteupDocEvent()
|
|
e.type = "changed_ballot_approval_text"
|
|
e.by = request.user.get_profile()
|
|
e.doc = doc
|
|
e.desc = u"Ballot approval text was generated"
|
|
e.text = unicode(mail)
|
|
e.save()
|
|
|
|
return e
|
|
|
|
def generate_approval_mail_approved(request, doc):
|
|
doc.full_status = full_intended_status(doc.intended_std_level)
|
|
status = doc.full_status.replace("a ", "").replace("an ", "")
|
|
|
|
if doc.intended_std_level_id in ("std", "ds", "ps", "bcp"):
|
|
action_type = "Protocol"
|
|
else:
|
|
action_type = "Document"
|
|
|
|
cc = []
|
|
cc.extend(settings.DOC_APPROVAL_EMAIL_CC)
|
|
|
|
# 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"):
|
|
doc.group.name_with_wg = doc.group.name + " Working Group"
|
|
if doc.group.list_email:
|
|
cc.append("%s mailing list <%s>" % (doc.group.acronym, doc.group.list_email))
|
|
cc.append("%s chair <%s-chairs@tools.ietf.org>" % (doc.group.acronym, doc.group.acronym))
|
|
else:
|
|
doc.group.name_with_wg = doc.group.name
|
|
|
|
doc.filled_title = textwrap.fill(doc.title, width=70, subsequent_indent=" " * 3)
|
|
|
|
if doc.group.type_id in ("individ", "area"):
|
|
made_by = "This document has been reviewed in the IETF but is not the product of an IETF Working Group."
|
|
else:
|
|
made_by = "This document is the product of the %s." % doc.group.name_with_wg
|
|
|
|
director = doc.ad
|
|
other_director = Person.objects.filter(role__group__role__person=director, role__group__role__name="ad").exclude(pk=director.pk)
|
|
|
|
if doc.group.type_id not in ("individ", "area") and other_director:
|
|
contacts = "The IESG contact persons are %s and %s." % (director.plain_name(), other_director[0].plain_name())
|
|
else:
|
|
contacts = "The IESG contact person is %s." % director.plain_name()
|
|
|
|
doc_type = "RFC" if doc.get_state_slug() == "rfc" else "Internet Draft"
|
|
|
|
return render_to_string("idrfc/approval_mail.txt",
|
|
dict(doc=doc,
|
|
docs=[doc],
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
|
cc=",\n ".join(cc),
|
|
doc_type=doc_type,
|
|
made_by=made_by,
|
|
contacts=contacts,
|
|
status=status,
|
|
action_type=action_type,
|
|
)
|
|
)
|
|
|
|
def generate_approval_mail_rfc_editorREDESIGN(request, doc):
|
|
full_status = full_intended_status(doc.intended_std_level)
|
|
status = full_status.replace("a ", "").replace("an ", "")
|
|
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 = []
|
|
if doc.group.type_id != "individ":
|
|
for r in doc.group.role_set.filter(name="chair").select_related():
|
|
to.append(r.formatted_email())
|
|
|
|
if doc.stream_id in ("ise", "irtf"):
|
|
# include ISE/IRTF chairs
|
|
g = Group.objects.get(acronym=doc.stream_id)
|
|
for r in g.role_set.filter(name="chair").select_related():
|
|
to.append(r.formatted_email())
|
|
|
|
if doc.stream_id == "irtf":
|
|
# include IRSG
|
|
to.append('"Internet Research Steering Group" <irsg@irtf.org>')
|
|
|
|
return render_to_string("idrfc/approval_mail_rfc_editor.txt",
|
|
dict(doc=doc,
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
|
doc_type=doc_type,
|
|
status=status,
|
|
full_status=full_status,
|
|
disapproved=disapproved,
|
|
to=", ".join(to),
|
|
)
|
|
)
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
generate_approval_mail = generate_approval_mailREDESIGN
|
|
generate_approval_mail_rfc_editor = generate_approval_mail_rfc_editorREDESIGN
|
|
|
|
|
|
def send_last_call_request(request, doc, ballot):
|
|
to = "iesg-secretary@ietf.org"
|
|
frm = '"DraftTracker Mail System" <iesg-secretary@ietf.org>'
|
|
docs = [d.document() for d in doc.idinternal.ballot_set()]
|
|
|
|
send_mail(request, to, frm,
|
|
"Last Call: %s" % doc.file_tag(),
|
|
"idrfc/last_call_request.txt",
|
|
dict(docs=docs,
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
|
|
|
def send_last_call_requestREDESIGN(request, doc):
|
|
to = "iesg-secretary@ietf.org"
|
|
frm = '"DraftTracker Mail System" <iesg-secretary@ietf.org>'
|
|
|
|
send_mail(request, to, frm,
|
|
"Last Call: %s" % doc.file_tag(),
|
|
"idrfc/last_call_request.txt",
|
|
dict(docs=[doc],
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
send_last_call_request = send_last_call_requestREDESIGN
|
|
|
|
def email_resurrect_requested(request, doc, by):
|
|
to = "I-D Administrator <internet-drafts@ietf.org>"
|
|
frm = u"%s <%s>" % by.person.email()
|
|
send_mail(request, to, frm,
|
|
"I-D Resurrection Request",
|
|
"idrfc/resurrect_request_email.txt",
|
|
dict(doc=doc,
|
|
by=frm,
|
|
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
|
|
|
def email_resurrect_requestedREDESIGN(request, doc, by):
|
|
to = "I-D Administrator <internet-drafts@ietf.org>"
|
|
|
|
if by.role_set.filter(name="secr", group__acronym="secretariat"):
|
|
e = by.role_email("secr", group="secretariat")
|
|
else:
|
|
e = by.role_email("ad")
|
|
frm = e.address
|
|
|
|
send_mail(request, to, e.formatted_email(),
|
|
"I-D Resurrection Request",
|
|
"idrfc/resurrect_request_email.txt",
|
|
dict(doc=doc,
|
|
by=frm,
|
|
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
email_resurrect_requested = email_resurrect_requestedREDESIGN
|
|
|
|
def email_resurrection_completed(request, doc):
|
|
to = u"%s <%s>" % doc.idinternal.resurrect_requested_by.person.email()
|
|
frm = "I-D Administrator <internet-drafts-reply@ietf.org>"
|
|
send_mail(request, to, frm,
|
|
"I-D Resurrection Completed - %s" % doc.file_tag(),
|
|
"idrfc/resurrect_completed_email.txt",
|
|
dict(doc=doc,
|
|
by=frm,
|
|
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()))
|
|
|
|
def email_resurrection_completedREDESIGN(request, doc, requester):
|
|
if requester.role_set.filter(name="secr", group__acronym="secretariat"):
|
|
e = requester.role_email("secr", group="secretariat")
|
|
else:
|
|
e = requester.role_email("ad")
|
|
|
|
to = e.formatted_email()
|
|
frm = "I-D Administrator <internet-drafts-reply@ietf.org>"
|
|
send_mail(request, to, frm,
|
|
"I-D Resurrection Completed - %s" % doc.file_tag(),
|
|
"idrfc/resurrect_completed_email.txt",
|
|
dict(doc=doc,
|
|
by=frm,
|
|
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()))
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
email_resurrection_completed = email_resurrection_completedREDESIGN
|
|
|
|
def email_ballot_deferred(request, doc, by, telechat_date):
|
|
to = "iesg@ietf.org"
|
|
frm = "DraftTracker Mail System <iesg-secretary@ietf.org>"
|
|
send_mail(request, to, frm,
|
|
"IESG Deferred Ballot notification: %s" % doc.file_tag(),
|
|
"idrfc/ballot_deferred_email.txt",
|
|
dict(doc=doc,
|
|
by=by,
|
|
telechat_date=telechat_date))
|
|
|
|
def generate_issue_ballot_mail(request, doc):
|
|
full_status = full_intended_status(doc.intended_status)
|
|
status = full_status.replace("a ", "").replace("an ", "")
|
|
|
|
ads = IESGLogin.objects.filter(user_level__in=(IESGLogin.AD_LEVEL, IESGLogin.INACTIVE_AD_LEVEL)).order_by('user_level', 'last_name')
|
|
positions = dict((p.ad_id, p) for p in doc.idinternal.ballot.positions.all())
|
|
|
|
# format positions
|
|
ad_positions = []
|
|
for ad in ads:
|
|
p = positions.get(ad.id)
|
|
if not p:
|
|
continue
|
|
|
|
def formatted(val):
|
|
if val > 0:
|
|
return "[ X ]"
|
|
elif val < 0:
|
|
return "[ . ]"
|
|
else:
|
|
return "[ ]"
|
|
|
|
fmt = u"%-21s%-10s%-11s%-9s%-10s" % (
|
|
unicode(ad)[:21],
|
|
formatted(p.yes),
|
|
formatted(p.noobj),
|
|
formatted(p.discuss),
|
|
"[ R ]" if p.recuse else formatted(p.abstain),
|
|
)
|
|
ad_positions.append((ad, fmt))
|
|
|
|
active_ad_positions = filter(lambda t: t[0].user_level == IESGLogin.AD_LEVEL, ad_positions)
|
|
inactive_ad_positions = filter(lambda t: t[0].user_level == IESGLogin.INACTIVE_AD_LEVEL, ad_positions)
|
|
|
|
# arrange discusses and comments
|
|
ad_feedback = []
|
|
discusses = dict((p.ad_id, p) for p in doc.idinternal.ballot.discusses.all()
|
|
if p.ad_id in positions and positions[p.ad_id].discuss == 1)
|
|
comments = dict((p.ad_id, p) for p in doc.idinternal.ballot.comments.all())
|
|
for ad in ads:
|
|
d = discusses.get(ad.id)
|
|
c = comments.get(ad.id)
|
|
if ad.user_level != IESGLogin.AD_LEVEL or not (c or d):
|
|
continue
|
|
|
|
ad_feedback.append((ad, d, c))
|
|
|
|
return render_to_string("idrfc/issue_ballot_mail.txt",
|
|
dict(doc=doc,
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
|
|
status=status,
|
|
active_ad_positions=active_ad_positions,
|
|
inactive_ad_positions=inactive_ad_positions,
|
|
ad_feedback=ad_feedback
|
|
)
|
|
)
|
|
|
|
def generate_issue_ballot_mailREDESIGN(request, doc):
|
|
full_status = full_intended_status(doc.intended_std_level)
|
|
status = full_status.replace("a ", "").replace("an ", "")
|
|
|
|
active_ads = Person.objects.filter(role__name="ad", role__group__state="active").distinct()
|
|
|
|
e = doc.latest_event(type="started_iesg_process")
|
|
positions = BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", time__gte=e.time).order_by("-time", '-id').select_related('ad')
|
|
|
|
# format positions and setup discusses and comments
|
|
ad_feedback = []
|
|
seen = set()
|
|
active_ad_positions = []
|
|
inactive_ad_positions = []
|
|
for p in positions:
|
|
if p.ad in seen:
|
|
continue
|
|
|
|
seen.add(p.ad)
|
|
|
|
def formatted(val):
|
|
if val:
|
|
return "[ X ]"
|
|
else:
|
|
return "[ ]"
|
|
|
|
fmt = u"%-21s%-10s%-11s%-9s%-10s" % (
|
|
p.ad.plain_name()[:21],
|
|
formatted(p.pos_id == "yes"),
|
|
formatted(p.pos_id == "noobj"),
|
|
formatted(p.pos_id == "discuss"),
|
|
"[ R ]" if p.pos_id == "recuse" else formatted(p.pos_id == "abstain"),
|
|
)
|
|
|
|
if p.ad in active_ads:
|
|
active_ad_positions.append(fmt)
|
|
if not p.pos_id == "discuss":
|
|
p.discuss = ""
|
|
if p.comment or p.discuss:
|
|
ad_feedback.append(p)
|
|
else:
|
|
inactive_ad_positions.append(fmt)
|
|
|
|
active_ad_positions.sort()
|
|
inactive_ad_positions.sort()
|
|
ad_feedback.sort(key=lambda p: p.ad.plain_name())
|
|
|
|
e = doc.latest_event(LastCallDocEvent, type="sent_last_call")
|
|
last_call_expires = e.expires if e else None
|
|
|
|
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_approval_text")
|
|
approval_text = e.text if e else ""
|
|
|
|
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
|
ballot_writeup = e.text if e else ""
|
|
|
|
# NOTE: according to Michelle Cotton <michelle.cotton@icann.org>
|
|
# (as per 2011-10-24) IANA is scraping these messages for
|
|
# information so would like to know beforehand if the format
|
|
# changes (perhaps RFC 6359 will change that)
|
|
return render_to_string("idrfc/issue_ballot_mailREDESIGN.txt",
|
|
dict(doc=doc,
|
|
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
|
status=status,
|
|
active_ad_positions=active_ad_positions,
|
|
inactive_ad_positions=inactive_ad_positions,
|
|
ad_feedback=ad_feedback,
|
|
last_call_expires=last_call_expires,
|
|
approval_text=approval_text,
|
|
ballot_writeup=ballot_writeup,
|
|
)
|
|
)
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
generate_issue_ballot_mail = generate_issue_ballot_mailREDESIGN
|
|
|
|
def email_iana(request, doc, to, msg):
|
|
# fix up message and send message to IANA for each in ballot set
|
|
import email
|
|
parsed_msg = email.message_from_string(msg.encode("utf-8"))
|
|
|
|
for i in doc.idinternal.ballot_set():
|
|
extra = {}
|
|
extra["Reply-To"] = "noreply@ietf.org"
|
|
extra["X-IETF-Draft-string"] = i.document().filename
|
|
extra["X-IETF-Draft-revision"] = i.document().revision_display()
|
|
|
|
send_mail_text(request, "To: IANA <%s>" % to,
|
|
parsed_msg["From"], parsed_msg["Subject"],
|
|
parsed_msg.get_payload(),
|
|
extra=extra,
|
|
bcc="fenner@research.att.com")
|
|
|
|
def email_ianaREDESIGN(request, doc, to, msg):
|
|
# 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"))
|
|
|
|
extra = {}
|
|
extra["Reply-To"] = "noreply@ietf.org"
|
|
extra["X-IETF-Draft-string"] = doc.name
|
|
extra["X-IETF-Draft-revision"] = doc.rev
|
|
|
|
send_mail_text(request, "IANA <%s>" % to,
|
|
parsed_msg["From"], parsed_msg["Subject"],
|
|
parsed_msg.get_payload(),
|
|
extra=extra,
|
|
bcc="fenner@research.att.com")
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
email_iana = email_ianaREDESIGN
|
|
|
|
def email_last_call_expired(doc):
|
|
text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.idinternal.cur_state.state
|
|
|
|
send_mail(None,
|
|
"iesg@ietf.org",
|
|
"DraftTracker Mail System <iesg-secretary@ietf.org>",
|
|
"Last Call Expired: %s" % doc.file_tag(),
|
|
"idrfc/change_notice.txt",
|
|
dict(text=text,
|
|
doc=doc,
|
|
url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url()),
|
|
cc="iesg-secretary@ietf.org")
|
|
|
|
def email_last_call_expiredREDESIGN(doc):
|
|
text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.get_state("draft-iesg").name
|
|
|
|
send_mail(None,
|
|
"iesg@ietf.org",
|
|
"DraftTracker Mail System <iesg-secretary@ietf.org>",
|
|
"Last Call Expired: %s" % doc.file_tag(),
|
|
"idrfc/change_notice.txt",
|
|
dict(text=text,
|
|
doc=doc,
|
|
url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url()),
|
|
cc="iesg-secretary@ietf.org")
|
|
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
email_last_call_expired = email_last_call_expiredREDESIGN
|
|
|