Skip to content

Commit 4b5ac9e

Browse files
committed
Indicate on the IESG Telechat Agenda if a document has an RFC Editor Note. To accomplish this, the RFC Editor Note needed to be separated from the rest of the ballot write up. Fixes ietf-tools#1230.
- Legacy-Id: 10770
1 parent 8ae439a commit 4b5ac9e

13 files changed

Lines changed: 201 additions & 11 deletions

File tree

ietf/doc/mails.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ def generate_ballot_writeup(request, doc):
9292

9393
return e
9494

95+
def generate_ballot_rfceditornote(request, doc):
96+
e = WriteupDocEvent()
97+
e.type = "changed_ballot_rfceditornote_text"
98+
e.by = request.user.person
99+
e.doc = doc
100+
e.desc = u"RFC Editor Note for ballot was generated"
101+
e.text = unicode(render_to_string("doc/mail/ballot_rfceditornote.txt"))
102+
e.save()
103+
104+
return e
105+
95106
def generate_last_call_announcement(request, doc):
96107
expiration_date = datetime.date.today() + datetime.timedelta(days=14)
97108
if doc.group.type_id in ("individ", "area"):

ietf/doc/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ def active_ballot(self):
232232
else:
233233
return None
234234

235+
def has_rfc_editor_note(self):
236+
e = self.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
237+
return bool(e and (e.text != ""))
238+
235239
def meeting_related(self):
236240
answer = False
237241
if self.type_id in ("agenda","minutes","bluesheets","slides"):
@@ -675,6 +679,7 @@ class DocReminder(models.Model):
675679

676680
("changed_ballot_approval_text", "Changed ballot approval text"),
677681
("changed_ballot_writeup_text", "Changed ballot writeup text"),
682+
("changed_rfc_editor_note_text", "Changed RFC Editor Note text"),
678683

679684
("changed_last_call_text", "Changed last call text"),
680685
("requested_last_call", "Requested last call"),

ietf/doc/tests.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,11 +707,19 @@ def test_writeup(self):
707707
text="This is ballot writeup notes.",
708708
by=Person.objects.get(name="(System)"))
709709

710+
rfced_note = WriteupDocEvent.objects.create(
711+
doc=doc,
712+
desc="Changed text",
713+
type="changed_rfc_editor_note_text",
714+
text="This is a note for the RFC Editor.",
715+
by=Person.objects.get(name="(System)"))
716+
710717
url = urlreverse('doc_writeup', kwargs=dict(name=doc.name))
711718
r = self.client.get(url)
712719
self.assertEqual(r.status_code, 200)
713720
self.assertTrue(appr.text in r.content)
714721
self.assertTrue(notes.text in r.content)
722+
self.assertTrue(rfced_note.text in r.content)
715723

716724
def test_history(self):
717725
doc = make_test_data()

ietf/doc/tests_ballot.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,45 @@ def test_edit_ballot_writeup(self):
273273
draft = Document.objects.get(name=draft.name)
274274
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text").text)
275275

276+
def test_edit_ballot_rfceditornote(self):
277+
draft = make_test_data()
278+
url = urlreverse('doc_ballot_rfceditornote', kwargs=dict(name=draft.name))
279+
login_testing_unauthorized(self, "secretary", url)
280+
281+
# add a note to the RFC Editor
282+
rfced_note = WriteupDocEvent.objects.create(
283+
doc=draft,
284+
desc="Changed text",
285+
type="changed_rfc_editor_note_text",
286+
text="This is a note for the RFC Editor.",
287+
by=Person.objects.get(name="(System)"))
288+
289+
# normal get
290+
r = self.client.get(url)
291+
self.assertEqual(r.status_code, 200)
292+
q = PyQuery(r.content)
293+
self.assertEqual(len(q('textarea[name=rfc_editor_note]')), 1)
294+
self.assertTrue(q('[type=submit]:contains("Save")'))
295+
self.assertTrue("<label class=\"control-label\">RFC Editor Note</label>" in r.content)
296+
self.assertTrue("This is a note for the RFC Editor" in r.content)
297+
298+
# save with a note
299+
r = self.client.post(url, dict(
300+
rfc_editor_note="This is a simple test.",
301+
save_ballot_rfceditornote="1"))
302+
self.assertEqual(r.status_code, 200)
303+
draft = Document.objects.get(name=draft.name)
304+
self.assertTrue(draft.has_rfc_editor_note())
305+
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text").text)
306+
307+
# clear the existing note
308+
r = self.client.post(url, dict(
309+
rfc_editor_note=" ",
310+
clear_ballot_rfceditornote="1"))
311+
self.assertEqual(r.status_code, 200)
312+
draft = Document.objects.get(name=draft.name)
313+
self.assertFalse(draft.has_rfc_editor_note())
314+
276315
def test_issue_ballot(self):
277316
draft = make_test_data()
278317
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
@@ -340,6 +379,55 @@ def test_edit_approval_text(self):
340379
draft = Document.objects.get(name=draft.name)
341380
self.assertTrue("Subject: Results of IETF-conflict review" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
342381

382+
def test_edit_verify_permissions(self):
383+
384+
def verify_fail(username, url):
385+
if username:
386+
self.client.login(username=username, password=username+"+password")
387+
r = self.client.get(url)
388+
self.assertEqual(r.status_code,403)
389+
390+
def verify_can_see(username, url):
391+
self.client.login(username=username, password=username+"+password")
392+
r = self.client.get(url)
393+
self.assertEqual(r.status_code,200)
394+
q = PyQuery(r.content)
395+
self.assertEqual(len(q("<textarea class=\"form-control\"")),1)
396+
397+
draft = make_test_data()
398+
399+
e = WriteupDocEvent()
400+
e.type = "changed_ballot_approval_text"
401+
e.by = Person.objects.get(name="(System)")
402+
e.doc = draft
403+
e.desc = u"Ballot approval text was generated"
404+
e.text = u"Test approval text."
405+
e.save()
406+
407+
e = WriteupDocEvent()
408+
e.type = "changed_ballot_writeup_text"
409+
e.by = Person.objects.get(name="(System)")
410+
e.doc = draft
411+
e.desc = u"Ballot writeup was generated"
412+
e.text = u"Test ballot writeup text."
413+
e.save()
414+
415+
e = WriteupDocEvent()
416+
e.type = "changed_ballot_rfceditornote_text"
417+
e.by = Person.objects.get(name="(System)")
418+
e.doc = draft
419+
e.desc = u"RFC Editor Note for ballot was generated"
420+
e.text = u"Test note to the RFC Editor text."
421+
e.save()
422+
423+
for p in ['doc_ballot_approvaltext','doc_ballot_writeupnotes','doc_ballot_rfceditornote']:
424+
url = urlreverse(p, kwargs=dict(name=draft.name))
425+
426+
for username in ['plain','marschairman','iana','iab chair']:
427+
verify_fail(username, url)
428+
429+
for username in ['secretary','ad']:
430+
verify_can_see(username, url)
343431

344432
class ApproveBallotTests(TestCase):
345433
def test_approve_ballot(self):

ietf/doc/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/undeferballot/$', views_ballot.undefer_ballot, name='doc_undefer_ballot'),
100100
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/lastcalltext/$', views_ballot.lastcalltext, name='doc_ballot_lastcall'),
101101
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ballotwriteupnotes/$', views_ballot.ballot_writeupnotes, name='doc_ballot_writeupnotes'),
102+
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ballotrfceditornote/$', views_ballot.ballot_rfceditornote, name='doc_ballot_rfceditornote'),
102103
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approvaltext/$', views_ballot.ballot_approvaltext, name='doc_ballot_approvaltext'),
103104
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approveballot/$', views_ballot.approve_ballot, name='doc_approve_ballot'),
104105
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/makelastcall/$', views_ballot.make_last_call, name='doc_make_last_call'),

ietf/doc/views_ballot.py

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
create_ballot_if_not_open, update_telechat )
2020
from ietf.doc.mails import ( email_ballot_deferred, email_ballot_undeferred,
2121
extra_automation_headers, generate_last_call_announcement,
22-
generate_issue_ballot_mail, generate_ballot_writeup, generate_approval_mail )
22+
generate_issue_ballot_mail, generate_ballot_writeup, generate_ballot_rfceditornote,
23+
generate_approval_mail )
2324
from ietf.doc.lastcall import request_last_call
2425
from ietf.iesg.models import TelechatDate
2526
from ietf.ietfauth.utils import has_role, role_required
@@ -585,6 +586,57 @@ def ballot_writeupnotes(request, name):
585586
),
586587
context_instance=RequestContext(request))
587588

589+
class BallotRfcEditorNoteForm(forms.Form):
590+
rfc_editor_note = forms.CharField(widget=forms.Textarea, label="RFC Editor Note", required=True)
591+
592+
def clean_rfc_editor_note(self):
593+
return self.cleaned_data["rfc_editor_note"].replace("\r", "")
594+
595+
@role_required('Area Director','Secretariat')
596+
def ballot_rfceditornote(request, name):
597+
"""Editing of RFC Editor Note in the ballot"""
598+
doc = get_object_or_404(Document, docalias__name=name)
599+
600+
login = request.user.person
601+
602+
603+
604+
existing = doc.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
605+
if not existing or (existing.text == ""):
606+
existing = generate_ballot_rfceditornote(request, doc)
607+
608+
form = BallotRfcEditorNoteForm(auto_id=False, initial=dict(rfc_editor_note=existing.text))
609+
610+
if request.method == 'POST' and "save_ballot_rfceditornote" in request.POST:
611+
form = BallotRfcEditorNoteForm(request.POST)
612+
if form.is_valid():
613+
t = form.cleaned_data["rfc_editor_note"]
614+
if t != existing.text:
615+
e = WriteupDocEvent(doc=doc, by=login)
616+
e.by = login
617+
e.type = "changed_rfc_editor_note_text"
618+
e.desc = "RFC Editor Note was changed"
619+
e.text = t.rstrip()
620+
e.save()
621+
622+
if request.method == 'POST' and "clear_ballot_rfceditornote" in request.POST:
623+
e = WriteupDocEvent(doc=doc, by=login)
624+
e.by = login
625+
e.type = "changed_rfc_editor_note_text"
626+
e.desc = "RFC Editor Note was cleared"
627+
e.text = ""
628+
e.save()
629+
630+
# make sure form shows a blank RFC Editor Note
631+
form = BallotRfcEditorNoteForm(initial=dict(rfc_editor_note=" "))
632+
633+
return render_to_response('doc/ballot/rfceditornote.html',
634+
dict(doc=doc,
635+
back_url=doc.get_absolute_url(),
636+
ballot_rfceditornote_form=form,
637+
),
638+
context_instance=RequestContext(request))
639+
588640
class ApprovalTextForm(forms.Form):
589641
approval_text = forms.CharField(widget=forms.Textarea, required=True)
590642

@@ -657,7 +709,19 @@ def approve_ballot(request, name):
657709
if not e:
658710
e = generate_ballot_writeup(request, doc)
659711
ballot_writeup = e.text
660-
712+
713+
error_duplicate_rfc_editor_note = False
714+
e = doc.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
715+
if e and (e.text != ""):
716+
if "RFC Editor Note" in ballot_writeup:
717+
error_duplicate_rfc_editor_note = True
718+
ballot_writeup += "\n\n" + e.text
719+
720+
if error_duplicate_rfc_editor_note:
721+
return render_to_response('doc/draft/rfceditor_note_duplicate_error.html',
722+
dict(doc=doc),
723+
context_instance=RequestContext(request))
724+
661725
if "NOT be published" in approval_text:
662726
action = "do_not_publish"
663727
elif "To: RFC Editor" in approval_text:

ietf/doc/views_doc.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,10 @@ def text_from_writeup(event_type):
691691
text_from_writeup("changed_ballot_writeup_text"),
692692
urlreverse("doc_ballot_writeupnotes", kwargs=dict(name=doc.name))))
693693

694+
writeups.append(("RFC Editor Note",
695+
text_from_writeup("changed_rfc_editor_note_text"),
696+
urlreverse("doc_ballot_rfceditornote", kwargs=dict(name=doc.name))))
697+
694698
elif doc.type_id == "charter":
695699
sections.append(("WG Review Announcement",
696700
"",

ietf/iesg/views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ def agenda_json(request, date=None):
156156
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
157157
if e:
158158
docinfo['consensus'] = e.consensus
159+
160+
docinfo['rfc-ed-note'] = doc.has_rfc_editor_note()
161+
159162
elif doc.type_id == 'conflrev':
160163
docinfo['rev'] = doc.rev
161164
td = doc.relateddocument_set.get(relationship__slug='conflrev').target.document

ietf/secr/telechat/views.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@ def get_doc_writeup(doc):
5757
want to display the contents of the document
5858
'''
5959
writeup = 'This document has no writeup'
60-
if doc.type_id in ('draft','charter'):
60+
if doc.type_id == 'draft':
61+
latest = doc.latest_event(WriteupDocEvent, type='changed_ballot_writeup_text')
62+
if latest and doc.has_rfc_editor_note:
63+
rfced_note = doc.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
64+
writeup = latest.text + "\n\n" + rfced_note.text
65+
else:
66+
writeup = latest.text
67+
if doc.type_id == 'charter':
6168
latest = doc.latest_event(WriteupDocEvent, type='changed_ballot_writeup_text')
6269
if latest:
6370
writeup = latest.text

ietf/templates/doc/ballot/writeupnotes.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{% extends "base.html" %}
2-
{# Copyright The IETF Trust 2015, All Rights Reserved #}
2+
{# Copyright The IETF Trust 2016, All Rights Reserved #}
33
{% load origin %}
44

55
{% load bootstrap3 %}
@@ -18,7 +18,7 @@ <h1>Ballot writeup and notes<br><small><a href="{% url "doc_view" name=doc.canon
1818
{% bootstrap_form ballot_writeup_form %}
1919

2020
<div class="help-block">
21-
Technical summary, Working Group summary, document quality, personnel, RFC Editor note, IRTF note, IESG note, IANA note. This text will be appended to all announcements and messages to the IRTF or RFC Editor.
21+
Technical summary, Working Group summary, document quality, personnel, IRTF note, IESG note, IANA note. This text will be appended to all announcements and messages to the IRTF or RFC Editor.
2222
</div>
2323

2424
{% buttons %}

0 commit comments

Comments
 (0)