From 0e2dd258c7eb1f96db9d2d95b31c82be7c98e3c2 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Tue, 17 Apr 2012 21:00:26 +0000 Subject: [PATCH] Made several changes to correctly use the new (RFC6410) "Internet Standard" level in email that gets sent at various stages in the handling of documents. Fixes bug 821 - Legacy-Id: 4288 --- ietf/idrfc/fixtures/base.xml | 4 +- ietf/idrfc/mails.py | 209 +----------------- ietf/idrfc/templatetags/mail_filters.py | 39 ++++ ietf/name/fixtures/names.xml | 6 +- ietf/name/models.py | 6 +- ietf/templates/idrfc/approval_mail.txt | 6 +- .../idrfc/approval_mail_rfc_editor.txt | 6 +- .../idrfc/issue_ballot_mailREDESIGN.txt | 4 +- .../idrfc/last_call_announcement.txt | 11 +- 9 files changed, 63 insertions(+), 228 deletions(-) create mode 100644 ietf/idrfc/templatetags/mail_filters.py diff --git a/ietf/idrfc/fixtures/base.xml b/ietf/idrfc/fixtures/base.xml index 97b6537a8..3d6a01d78 100644 --- a/ietf/idrfc/fixtures/base.xml +++ b/ietf/idrfc/fixtures/base.xml @@ -1083,7 +1083,7 @@ Proposed Standard - Standard + Internet Standard None @@ -1329,4 +1329,4 @@ withdrawn, etc.) Date for List of Approved V-00 Submissions from WG Chairs sixth - \ No newline at end of file + diff --git a/ietf/idrfc/mails.py b/ietf/idrfc/mails.py index 4b7bcb78f..7e0a2709a 100644 --- a/ietf/idrfc/mails.py +++ b/ietf/idrfc/mails.py @@ -72,26 +72,6 @@ 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" @@ -104,48 +84,9 @@ def generate_ballot_writeup(request, doc): 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, - ) - ) + pass 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 = [] @@ -174,8 +115,6 @@ def generate_last_call_announcementREDESIGN(request, doc): 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, ) ) @@ -195,85 +134,10 @@ 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, - ) - ) + pass 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" - - from ietf.ietfworkflows.streams import get_stream_from_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) " - - 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, - ) - ) + pass DO_NOT_PUBLISH_IESG_STATES = ("nopubadw", "nopubanw") @@ -294,8 +158,6 @@ def generate_approval_mailREDESIGN(request, doc): 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" @@ -340,14 +202,11 @@ def generate_approval_mail_approved(request, doc): 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" @@ -370,8 +229,6 @@ def generate_approval_mail_rfc_editorREDESIGN(request, doc): 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), ) @@ -474,66 +331,9 @@ def email_ballot_deferred(request, doc, by, telechat_date): 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 - ) - ) + pass 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") @@ -593,7 +393,6 @@ def generate_issue_ballot_mailREDESIGN(request, doc): 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, diff --git a/ietf/idrfc/templatetags/mail_filters.py b/ietf/idrfc/templatetags/mail_filters.py new file mode 100644 index 000000000..8477cb4e3 --- /dev/null +++ b/ietf/idrfc/templatetags/mail_filters.py @@ -0,0 +1,39 @@ +from django import template +from django.core.cache import cache +from django.template import loader +from ietf.idtracker.models import Area + +register = template.Library() + +@register.filter(name='std_level_prompt') +def std_level_prompt(doc): + """ + Returns the name from the std level names table corresponding + to the object's intended_std_level (with the word RFC appended in some + cases), or a prompt requesting that the intended_std_level be set.""" + + prompt = "*** YOU MUST SELECT AN INTENDED STATUS FOR THIS DRAFT AND REGENERATE THIS TEXT ***" + + if doc.intended_std_level: + prompt = doc.intended_std_level.name + if doc.intended_std_level_id in ('inf','exp','hist'): + prompt = prompt + " RFC" + + return prompt + + +@register.filter(name='std_level_prompt_with_article') +def std_level_prompt_with_article(doc): + """ + Returns the standard level prompt prefixed with an appropriate article.""" + + # This is a very crude way to select between "a" and "an", but will + # work for the standards levels in the standards level names table + # Grammar war alert: This will generate "an historic" + article = "" + if doc.intended_std_level: + article = "a" + if doc.intended_std_level.name[0].lower() in "aehiou": + article = "an" + return article+" "+std_level_prompt(doc) + diff --git a/ietf/name/fixtures/names.xml b/ietf/name/fixtures/names.xml index 279f7268a..3978aa433 100644 --- a/ietf/name/fixtures/names.xml +++ b/ietf/name/fixtures/names.xml @@ -409,7 +409,7 @@ 2 - Standard + Internet Standard True 3 @@ -583,7 +583,7 @@ 0 - Standard + Internet Standard True 0 @@ -1581,4 +1581,4 @@ 2 - \ No newline at end of file + diff --git a/ietf/name/models.py b/ietf/name/models.py index a5512e816..50f914702 100644 --- a/ietf/name/models.py +++ b/ietf/name/models.py @@ -34,11 +34,11 @@ class DocTagName(NameModel): """Waiting for Reference, IANA Coordination, Revised ID Needed, External Party, AD Followup, Point Raised - Writeup Needed, ...""" class StdLevelName(NameModel): - """Proposed Standard, Draft Standard, Standard, Experimental, + """Proposed Standard, (Draft Standard), Internet Standard, Experimental, Informational, Best Current Practice, Historic, ...""" class IntendedStdLevelName(NameModel): - """Standards Track, Experimental, Informational, Best Current - Practice, Historic, ...""" + """Proposed Standard, (Draft Standard), Internet Standard, Experimental, + Informational, Best Current Practice, Historic, ...""" class DocReminderTypeName(NameModel): "Stream state" class BallotPositionName(NameModel): diff --git a/ietf/templates/idrfc/approval_mail.txt b/ietf/templates/idrfc/approval_mail.txt index b9cde2f43..1be6fcd9b 100644 --- a/ietf/templates/idrfc/approval_mail.txt +++ b/ietf/templates/idrfc/approval_mail.txt @@ -1,11 +1,11 @@ -{% load ietf_filters %}{% autoescape off %}From: The IESG +{% load ietf_filters %}{%load mail_filters %}{% autoescape off %}From: The IESG To: IETF-Announce {% if cc %} Cc: {{ cc }}{% endif %} -Subject: {{ action_type }} Action: '{{ doc.title|clean_whitespace }}' to {{ status }} ({{ doc.filename_with_rev }}) +Subject: {{ action_type }} Action: '{{ doc.title|clean_whitespace }}' to {{ doc|std_level_prompt }} ({{ doc.filename_with_rev }}) {% filter wordwrap:73 %}The IESG has approved the following document{{ docs|pluralize }}:{% for d in docs %} - '{{ d.filled_title }}' - ({{ d.filename_with_rev }}) as {{ d.full_status }}{% endfor %} + ({{ d.filename_with_rev }}) as {{ d|std_level_prompt }}{% endfor %} {{ made_by }} diff --git a/ietf/templates/idrfc/approval_mail_rfc_editor.txt b/ietf/templates/idrfc/approval_mail_rfc_editor.txt index 4fcbde9b6..fe9fa3c77 100644 --- a/ietf/templates/idrfc/approval_mail_rfc_editor.txt +++ b/ietf/templates/idrfc/approval_mail_rfc_editor.txt @@ -1,13 +1,13 @@ -{% autoescape off %}From: The IESG +{% load mail_filters %}{% autoescape off %}From: The IESG To: {{to}} Cc: The IESG , , Subject: Results of IETF-conflict review for {{ doc.file_tag }} {% filter wordwrap:73 %} The IESG has completed a review of <{{ doc.name }}> consistent with RFC5742. This review is applied to all non-IETF streams. {% if disapproved %} -The IESG recommends that '{{ doc.title }}' {{ doc.file_tag|safe }} NOT be published as {{ full_status }}. +The IESG recommends that '{{ doc.title }}' {{ doc.file_tag|safe }} NOT be published as {{ doc|std_level_prompt_with_article }}. {% else %} -The IESG has no problem with the publication of '{{ doc.title }}' {{ doc.file_tag|safe }} as {{ full_status }}. +The IESG has no problem with the publication of '{{ doc.title }}' {{ doc.file_tag|safe }} as {{ doc|std_level_prompt_with_article }}. The IESG would also like the IRSG or RFC-Editor to review the comments in the datatracker ({{ doc_url }}) related to this document and determine whether or not they merit incorporation into the document. Comments may exist in both the ballot and the history log.{% endif %} diff --git a/ietf/templates/idrfc/issue_ballot_mailREDESIGN.txt b/ietf/templates/idrfc/issue_ballot_mailREDESIGN.txt index bced9e27c..b5623968e 100644 --- a/ietf/templates/idrfc/issue_ballot_mailREDESIGN.txt +++ b/ietf/templates/idrfc/issue_ballot_mailREDESIGN.txt @@ -1,7 +1,7 @@ -{% autoescape off %}To: Internet Engineering Steering Group +{% load mail_filters %}{% autoescape off %}To: Internet Engineering Steering Group From: IESG Secretary Reply-To: IESG Secretary -Subject: Evaluation: {{ doc.file_tag }} to {{ status }} +Subject: Evaluation: {{ doc.file_tag }} to {{ doc|std_level_prompt }} {% filter wordwrap:73 %}Evaluation for {{ doc.file_tag }} can be found at {{ doc_url }} diff --git a/ietf/templates/idrfc/last_call_announcement.txt b/ietf/templates/idrfc/last_call_announcement.txt index 19ff2a68d..8c3a55473 100644 --- a/ietf/templates/idrfc/last_call_announcement.txt +++ b/ietf/templates/idrfc/last_call_announcement.txt @@ -1,13 +1,13 @@ -{% load ietf_filters %}{% autoescape off %}From: The IESG +{% load ietf_filters %}{% load mail_filters %}{% autoescape off %}From: The IESG To: IETF-Announce {% if cc %} CC: {{ cc }}{% endif %} Reply-To: ietf@ietf.org -Subject: Last Call: {{ doc.file_tag }} ({{ doc.title|clean_whitespace }}) to {{ status }} +Subject: Last Call: {{ doc.file_tag }} ({{ doc.title|clean_whitespace }}) to {{ doc|std_level_prompt }} {% filter wordwrap:73 %} The IESG has received a request from {{ group }} to consider the following document{{ docs|pluralize }}:{% for d in docs %} - '{{ d.filled_title }}' - {{ d.file_tag }} as {{ d.full_status }}{% endfor %} + {{ d.file_tag }} as {{ d|std_level_prompt }}{% endfor %} The IESG plans to make a decision in the next few weeks, and solicits final comments on this action. Please send substantive comments to the ietf@ietf.org mailing lists by {{ expiration_date }}. Exceptionally, comments may be sent to iesg@ietf.org instead. In either case, please retain the beginning of the Subject line to allow automated sorting.{% endfilter %} @@ -20,10 +20,7 @@ Abstract{{ docs|pluralize }} The file{{ urls|pluralize }} can be obtained via {% for u in urls %}{{ u }} -{% endfor %}{% if impl_report %} -Implementation Report can be accessed at -http://www.ietf.org/iesg/implementation.html -{% endif %} +{% endfor %} IESG discussion can be tracked via {{ doc_url }}