Skip to content

Commit 0e2dd25

Browse files
committed
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
1 parent bf718d1 commit 0e2dd25

9 files changed

Lines changed: 63 additions & 228 deletions

File tree

ietf/idrfc/fixtures/base.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@
10831083
<field type="CharField" name="intended_status">Proposed Standard</field>
10841084
</object>
10851085
<object pk="7" model="idtracker.idintendedstatus">
1086-
<field type="CharField" name="intended_status">Standard</field>
1086+
<field type="CharField" name="intended_status">Internet Standard</field>
10871087
</object>
10881088
<object pk="8" model="idtracker.idintendedstatus">
10891089
<field type="CharField" name="intended_status">None</field>
@@ -1329,4 +1329,4 @@ withdrawn, etc.)</field>
13291329
<field type="CharField" name="description">Date for List of Approved V-00 Submissions from WG Chairs</field>
13301330
<field type="CharField" name="f_name">sixth</field>
13311331
</object>
1332-
</django-objects>
1332+
</django-objects>

ietf/idrfc/mails.py

Lines changed: 4 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -72,26 +72,6 @@ def email_adREDESIGN(request, doc, ad, changed_by, text, subject=None):
7272
email_owner = email_adREDESIGN
7373

7474

75-
def full_intended_status(intended_status):
76-
s = str(intended_status)
77-
# FIXME: this should perhaps be defined in the db
78-
if "Informational" in s:
79-
return "an Informational RFC"
80-
elif "Experimental" in s:
81-
return "an Experimental RFC"
82-
elif "Proposed" in s:
83-
return "a Proposed Standard"
84-
elif "Draft" in s:
85-
return "a Draft Standard"
86-
elif "BCP" in s:
87-
return "a BCP"
88-
elif "Standard" in s:
89-
return "a Full Standard"
90-
elif "Request" in s or "None" in s:
91-
return "*** YOU MUST SELECT AN INTENDED STATUS FOR THIS DRAFT AND REGENERATE THIS TEXT ***"
92-
else:
93-
return "a %s" % s
94-
9575
def generate_ballot_writeup(request, doc):
9676
e = WriteupDocEvent()
9777
e.type = "changed_ballot_writeup_text"
@@ -104,48 +84,9 @@ def generate_ballot_writeup(request, doc):
10484
return e
10585

10686
def generate_last_call_announcement(request, doc):
107-
status = full_intended_status(doc.intended_status).replace("a ", "").replace("an ", "")
108-
109-
expiration_date = date.today() + timedelta(days=14)
110-
cc = []
111-
if doc.group.acronym_id == Acronym.INDIVIDUAL_SUBMITTER:
112-
group = "an individual submitter"
113-
expiration_date += timedelta(days=14)
114-
else:
115-
group = "the %s WG (%s)" % (doc.group.name, doc.group.acronym)
116-
cc.append(doc.group.ietfwg.email_address)
117-
118-
urls = []
119-
docs = [d.document() for d in doc.idinternal.ballot_set()]
120-
for d in docs:
121-
d.full_status = full_intended_status(d.intended_status)
122-
d.filled_title = textwrap.fill(d.title, width=70, subsequent_indent=" " * 3)
123-
urls.append(settings.IDTRACKER_BASE_URL + d.idinternal.get_absolute_url())
124-
125-
iprs, docs = iprs_from_docs(docs)
126-
if iprs:
127-
ipr_links = [ urlreverse("ietf.ipr.views.show", kwargs=dict(ipr_id=i.ipr_id)) for i in iprs]
128-
ipr_links = [ settings.IDTRACKER_BASE_URL+url if not url.startswith("http") else url for url in ipr_links ]
129-
else:
130-
ipr_links = None
131-
132-
return render_to_string("idrfc/last_call_announcement.txt",
133-
dict(doc=doc,
134-
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
135-
expiration_date=expiration_date.strftime("%Y-%m-%d"), #.strftime("%B %-d, %Y"),
136-
cc=", ".join("<%s>" % e for e in cc),
137-
group=group,
138-
docs=docs,
139-
urls=urls,
140-
status=status,
141-
impl_report="Draft" in status or "Full" in status,
142-
ipr_links=ipr_links,
143-
)
144-
)
87+
pass
14588

14689
def generate_last_call_announcementREDESIGN(request, doc):
147-
doc.full_status = full_intended_status(doc.intended_std_level)
148-
status = doc.full_status.replace("a ", "").replace("an ", "")
14990

15091
expiration_date = date.today() + timedelta(days=14)
15192
cc = []
@@ -174,8 +115,6 @@ def generate_last_call_announcementREDESIGN(request, doc):
174115
group=group,
175116
docs=[ doc ],
176117
urls=[ settings.IDTRACKER_BASE_URL + doc.get_absolute_url() ],
177-
status=status,
178-
impl_report="Draft" in status or "Full" in status,
179118
ipr_links=ipr_links,
180119
)
181120
)
@@ -195,85 +134,10 @@ def generate_last_call_announcementREDESIGN(request, doc):
195134
generate_last_call_announcement = generate_last_call_announcementREDESIGN
196135

197136
def generate_approval_mail(request, doc):
198-
if doc.idinternal.cur_state_id in IDState.DO_NOT_PUBLISH_STATES or doc.idinternal.via_rfc_editor:
199-
return generate_approval_mail_rfc_editor(request, doc)
200-
201-
status = full_intended_status(doc.intended_status).replace("a ", "").replace("an ", "")
202-
if "an " in full_intended_status(doc.intended_status):
203-
action_type = "Document"
204-
else:
205-
action_type = "Protocol"
206-
207-
cc = settings.DOC_APPROVAL_EMAIL_CC
208-
209-
if doc.group.ietfwg.group_type.type != "AG" and not doc.group.name.endswith("Working Group"):
210-
doc.group.name_with_wg = doc.group.name + " Working Group"
211-
cc.append("%s mailing list <%s>" % (doc.group.acronym, doc.group.ietfwg.email_address))
212-
cc.append("%s chair <%s-chairs@tools.ietf.org>" % (doc.group.acronym, doc.group.acronym))
213-
else:
214-
doc.group.name_with_wg = doc.group.name
215-
216-
docs = [d.document() for d in doc.idinternal.ballot_set()]
217-
for d in docs:
218-
d.full_status = full_intended_status(d.intended_status)
219-
d.filled_title = textwrap.fill(d.title, width=70, subsequent_indent=" " * 3)
220-
221-
if doc.group.acronym_id == Acronym.INDIVIDUAL_SUBMITTER:
222-
if len(docs) > 1:
223-
made_by = "These documents have been reviewed in the IETF but are not the products of an IETF Working Group."
224-
else:
225-
made_by = "This document has been reviewed in the IETF but is not the product of an IETF Working Group."
226-
else:
227-
if len(docs) > 1:
228-
made_by = "These documents are products of the %s." % doc.group.name_with_wg
229-
else:
230-
made_by = "This document is the product of the %s." % doc.group.name_with_wg
231-
232-
director = doc.idinternal.job_owner
233-
other_director = IESGLogin.objects.filter(person__in=[ad.person for ad in doc.group.ietfwg.area_directors()]).exclude(id=doc.idinternal.job_owner_id)
234-
if doc.group.acronym_id != Acronym.INDIVIDUAL_SUBMITTER and other_director:
235-
contacts = "The IESG contact persons are %s and %s." % (director, other_director[0])
236-
else:
237-
contacts = "The IESG contact person is %s." % director
238-
239-
doc_type = "RFC" if type(doc) == Rfc else "Internet Draft"
240-
241-
return render_to_string("idrfc/approval_mail.txt",
242-
dict(doc=doc,
243-
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
244-
cc=",\n ".join(cc),
245-
docs=docs,
246-
doc_type=doc_type,
247-
made_by=made_by,
248-
contacts=contacts,
249-
status=status,
250-
action_type=action_type,
251-
)
252-
)
137+
pass
253138

254139
def generate_approval_mail_rfc_editor(request, doc):
255-
full_status = full_intended_status(doc.intended_status)
256-
status = full_status.replace("a ", "").replace("an ", "")
257-
disapproved = doc.idinternal.cur_state_id in IDState.DO_NOT_PUBLISH_STATES
258-
doc_type = "RFC" if type(doc) == Rfc else "Internet Draft"
259-
260-
from ietf.ietfworkflows.streams import get_stream_from_draft
261-
stream = get_stream_from_draft(doc)
262-
to = ", ".join([u"%s <%s>" % x.email() for x in stream.get_chairs_for_document(doc) ])
263-
if stream.name == "IRTF":
264-
# also send to the IRSG
265-
to += ", Internet Research Steering Group (IRSG) <irsg@irtf.org>"
266-
267-
return render_to_string("idrfc/approval_mail_rfc_editor.txt",
268-
dict(doc=doc,
269-
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
270-
doc_type=doc_type,
271-
status=status,
272-
full_status=full_status,
273-
disapproved=disapproved,
274-
to=to,
275-
)
276-
)
140+
pass
277141

278142
DO_NOT_PUBLISH_IESG_STATES = ("nopubadw", "nopubanw")
279143

@@ -294,8 +158,6 @@ def generate_approval_mailREDESIGN(request, doc):
294158
return e
295159

296160
def generate_approval_mail_approved(request, doc):
297-
doc.full_status = full_intended_status(doc.intended_std_level)
298-
status = doc.full_status.replace("a ", "").replace("an ", "")
299161

300162
if doc.intended_std_level_id in ("std", "ds", "ps", "bcp"):
301163
action_type = "Protocol"
@@ -340,14 +202,11 @@ def generate_approval_mail_approved(request, doc):
340202
doc_type=doc_type,
341203
made_by=made_by,
342204
contacts=contacts,
343-
status=status,
344205
action_type=action_type,
345206
)
346207
)
347208

348209
def generate_approval_mail_rfc_editorREDESIGN(request, doc):
349-
full_status = full_intended_status(doc.intended_std_level)
350-
status = full_status.replace("a ", "").replace("an ", "")
351210
disapproved = doc.get_state_slug("draft-iesg") in DO_NOT_PUBLISH_IESG_STATES
352211
doc_type = "RFC" if doc.get_state_slug() == "rfc" else "Internet Draft"
353212

@@ -370,8 +229,6 @@ def generate_approval_mail_rfc_editorREDESIGN(request, doc):
370229
dict(doc=doc,
371230
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
372231
doc_type=doc_type,
373-
status=status,
374-
full_status=full_status,
375232
disapproved=disapproved,
376233
to=", ".join(to),
377234
)
@@ -474,66 +331,9 @@ def email_ballot_deferred(request, doc, by, telechat_date):
474331
telechat_date=telechat_date))
475332

476333
def generate_issue_ballot_mail(request, doc):
477-
full_status = full_intended_status(doc.intended_status)
478-
status = full_status.replace("a ", "").replace("an ", "")
479-
480-
ads = IESGLogin.objects.filter(user_level__in=(IESGLogin.AD_LEVEL, IESGLogin.INACTIVE_AD_LEVEL)).order_by('user_level', 'last_name')
481-
positions = dict((p.ad_id, p) for p in doc.idinternal.ballot.positions.all())
482-
483-
# format positions
484-
ad_positions = []
485-
for ad in ads:
486-
p = positions.get(ad.id)
487-
if not p:
488-
continue
489-
490-
def formatted(val):
491-
if val > 0:
492-
return "[ X ]"
493-
elif val < 0:
494-
return "[ . ]"
495-
else:
496-
return "[ ]"
497-
498-
fmt = u"%-21s%-10s%-11s%-9s%-10s" % (
499-
unicode(ad)[:21],
500-
formatted(p.yes),
501-
formatted(p.noobj),
502-
formatted(p.discuss),
503-
"[ R ]" if p.recuse else formatted(p.abstain),
504-
)
505-
ad_positions.append((ad, fmt))
506-
507-
active_ad_positions = filter(lambda t: t[0].user_level == IESGLogin.AD_LEVEL, ad_positions)
508-
inactive_ad_positions = filter(lambda t: t[0].user_level == IESGLogin.INACTIVE_AD_LEVEL, ad_positions)
509-
510-
# arrange discusses and comments
511-
ad_feedback = []
512-
discusses = dict((p.ad_id, p) for p in doc.idinternal.ballot.discusses.all()
513-
if p.ad_id in positions and positions[p.ad_id].discuss == 1)
514-
comments = dict((p.ad_id, p) for p in doc.idinternal.ballot.comments.all())
515-
for ad in ads:
516-
d = discusses.get(ad.id)
517-
c = comments.get(ad.id)
518-
if ad.user_level != IESGLogin.AD_LEVEL or not (c or d):
519-
continue
520-
521-
ad_feedback.append((ad, d, c))
522-
523-
return render_to_string("idrfc/issue_ballot_mail.txt",
524-
dict(doc=doc,
525-
doc_url=settings.IDTRACKER_BASE_URL + doc.idinternal.get_absolute_url(),
526-
status=status,
527-
active_ad_positions=active_ad_positions,
528-
inactive_ad_positions=inactive_ad_positions,
529-
ad_feedback=ad_feedback
530-
)
531-
)
334+
pass
532335

533336
def generate_issue_ballot_mailREDESIGN(request, doc):
534-
full_status = full_intended_status(doc.intended_std_level)
535-
status = full_status.replace("a ", "").replace("an ", "")
536-
537337
active_ads = Person.objects.filter(role__name="ad", role__group__state="active").distinct()
538338

539339
e = doc.latest_event(type="started_iesg_process")
@@ -593,7 +393,6 @@ def formatted(val):
593393
return render_to_string("idrfc/issue_ballot_mailREDESIGN.txt",
594394
dict(doc=doc,
595395
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
596-
status=status,
597396
active_ad_positions=active_ad_positions,
598397
inactive_ad_positions=inactive_ad_positions,
599398
ad_feedback=ad_feedback,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from django import template
2+
from django.core.cache import cache
3+
from django.template import loader
4+
from ietf.idtracker.models import Area
5+
6+
register = template.Library()
7+
8+
@register.filter(name='std_level_prompt')
9+
def std_level_prompt(doc):
10+
"""
11+
Returns the name from the std level names table corresponding
12+
to the object's intended_std_level (with the word RFC appended in some
13+
cases), or a prompt requesting that the intended_std_level be set."""
14+
15+
prompt = "*** YOU MUST SELECT AN INTENDED STATUS FOR THIS DRAFT AND REGENERATE THIS TEXT ***"
16+
17+
if doc.intended_std_level:
18+
prompt = doc.intended_std_level.name
19+
if doc.intended_std_level_id in ('inf','exp','hist'):
20+
prompt = prompt + " RFC"
21+
22+
return prompt
23+
24+
25+
@register.filter(name='std_level_prompt_with_article')
26+
def std_level_prompt_with_article(doc):
27+
"""
28+
Returns the standard level prompt prefixed with an appropriate article."""
29+
30+
# This is a very crude way to select between "a" and "an", but will
31+
# work for the standards levels in the standards level names table
32+
# Grammar war alert: This will generate "an historic"
33+
article = ""
34+
if doc.intended_std_level:
35+
article = "a"
36+
if doc.intended_std_level.name[0].lower() in "aehiou":
37+
article = "an"
38+
return article+" "+std_level_prompt(doc)
39+

ietf/name/fixtures/names.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@
409409
<field type="IntegerField" name="order">2</field>
410410
</object>
411411
<object pk="std" model="name.intendedstdlevelname">
412-
<field type="CharField" name="name">Standard</field>
412+
<field type="CharField" name="name">Internet Standard</field>
413413
<field type="TextField" name="desc"></field>
414414
<field type="BooleanField" name="used">True</field>
415415
<field type="IntegerField" name="order">3</field>
@@ -583,7 +583,7 @@
583583
<field type="IntegerField" name="order">0</field>
584584
</object>
585585
<object pk="std" model="name.stdlevelname">
586-
<field type="CharField" name="name">Standard</field>
586+
<field type="CharField" name="name">Internet Standard</field>
587587
<field type="TextField" name="desc"></field>
588588
<field type="BooleanField" name="used">True</field>
589589
<field type="IntegerField" name="order">0</field>
@@ -1581,4 +1581,4 @@
15811581
<field type="IntegerField" name="order">2</field>
15821582
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
15831583
</object>
1584-
</django-objects>
1584+
</django-objects>

ietf/name/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ class DocTagName(NameModel):
3434
"""Waiting for Reference, IANA Coordination, Revised ID Needed,
3535
External Party, AD Followup, Point Raised - Writeup Needed, ..."""
3636
class StdLevelName(NameModel):
37-
"""Proposed Standard, Draft Standard, Standard, Experimental,
37+
"""Proposed Standard, (Draft Standard), Internet Standard, Experimental,
3838
Informational, Best Current Practice, Historic, ..."""
3939
class IntendedStdLevelName(NameModel):
40-
"""Standards Track, Experimental, Informational, Best Current
41-
Practice, Historic, ..."""
40+
"""Proposed Standard, (Draft Standard), Internet Standard, Experimental,
41+
Informational, Best Current Practice, Historic, ..."""
4242
class DocReminderTypeName(NameModel):
4343
"Stream state"
4444
class BallotPositionName(NameModel):

ietf/templates/idrfc/approval_mail.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
{% load ietf_filters %}{% autoescape off %}From: The IESG <iesg-secretary@ietf.org>
1+
{% load ietf_filters %}{%load mail_filters %}{% autoescape off %}From: The IESG <iesg-secretary@ietf.org>
22
To: IETF-Announce <ietf-announce@ietf.org>{% if cc %}
33
Cc: {{ cc }}{% endif %}
4-
Subject: {{ action_type }} Action: '{{ doc.title|clean_whitespace }}' to {{ status }} ({{ doc.filename_with_rev }})
4+
Subject: {{ action_type }} Action: '{{ doc.title|clean_whitespace }}' to {{ doc|std_level_prompt }} ({{ doc.filename_with_rev }})
55

66
{% filter wordwrap:73 %}The IESG has approved the following document{{ docs|pluralize }}:{% for d in docs %}
77
- '{{ d.filled_title }}'
8-
({{ d.filename_with_rev }}) as {{ d.full_status }}{% endfor %}
8+
({{ d.filename_with_rev }}) as {{ d|std_level_prompt }}{% endfor %}
99

1010
{{ made_by }}
1111

0 commit comments

Comments
 (0)