Skip to content

Commit fddaf58

Browse files
committed
Merged [4288] from rjsparks@nostrum.com:
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: 4332 Note: SVN reference [4288] has been migrated to Git commit 0e2dd25
2 parents d383fac + 0e2dd25 commit fddaf58

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")
@@ -589,7 +389,6 @@ def formatted(val):
589389
return render_to_string("idrfc/issue_ballot_mailREDESIGN.txt",
590390
dict(doc=doc,
591391
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
592-
status=status,
593392
active_ad_positions=active_ad_positions,
594393
inactive_ad_positions=inactive_ad_positions,
595394
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)