Merged in [10770], [10771], [10772], and [10773] from housley@vigilsec.com:
The IESG Telechat Agenda now shows "(Has RFC Editor Note)" after the I-D filename if there is an RFC Editor Note associated with the document. This was added to the html and txt versions of the agenda. It was not added to the Secretariat view or the Scribe view of the agenda. For transition, when an AD edits the RFC Editor Note, they need to move the text from the current writeup into the new field. Returning documents on the telechat agenda seems to be the biggest opportunity for something to fall between the cracks. If an event of type "changed_rfc_editor_note' exists, and the string "RFC Editor Note" appears in the text of the most recent 'changed_ballot_writeup_text' event, then a message is shown that tells the AD to remove the RFC Editor Note from the writeup. - Legacy-Id: 10783 Note: SVN reference [10770] has been migrated to Git commit4b5ac9e09e
Note: SVN reference [10771] has been migrated to Git commit46589ee421
Note: SVN reference [10772] has been migrated to Git commitc73659e95c
Note: SVN reference [10773] has been migrated to Git commit2e6633c016
This commit is contained in:
commit
174cfeafa3
|
@ -92,6 +92,17 @@ def generate_ballot_writeup(request, doc):
|
|||
|
||||
return e
|
||||
|
||||
def generate_ballot_rfceditornote(request, doc):
|
||||
e = WriteupDocEvent()
|
||||
e.type = "changed_ballot_rfceditornote_text"
|
||||
e.by = request.user.person
|
||||
e.doc = doc
|
||||
e.desc = u"RFC Editor Note for ballot was generated"
|
||||
e.text = unicode(render_to_string("doc/mail/ballot_rfceditornote.txt"))
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
||||
def generate_last_call_announcement(request, doc):
|
||||
expiration_date = datetime.date.today() + datetime.timedelta(days=14)
|
||||
if doc.group.type_id in ("individ", "area"):
|
||||
|
|
|
@ -232,6 +232,10 @@ class DocumentInfo(models.Model):
|
|||
else:
|
||||
return None
|
||||
|
||||
def has_rfc_editor_note(self):
|
||||
e = self.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
|
||||
return bool(e and (e.text != ""))
|
||||
|
||||
def meeting_related(self):
|
||||
answer = False
|
||||
if self.type_id in ("agenda","minutes","bluesheets","slides","recording"):
|
||||
|
@ -675,6 +679,7 @@ EVENT_TYPES = [
|
|||
|
||||
("changed_ballot_approval_text", "Changed ballot approval text"),
|
||||
("changed_ballot_writeup_text", "Changed ballot writeup text"),
|
||||
("changed_rfc_editor_note_text", "Changed RFC Editor Note text"),
|
||||
|
||||
("changed_last_call_text", "Changed last call text"),
|
||||
("requested_last_call", "Requested last call"),
|
||||
|
|
|
@ -710,11 +710,19 @@ class DocTestCase(TestCase):
|
|||
text="This is ballot writeup notes.",
|
||||
by=Person.objects.get(name="(System)"))
|
||||
|
||||
rfced_note = WriteupDocEvent.objects.create(
|
||||
doc=doc,
|
||||
desc="Changed text",
|
||||
type="changed_rfc_editor_note_text",
|
||||
text="This is a note for the RFC Editor.",
|
||||
by=Person.objects.get(name="(System)"))
|
||||
|
||||
url = urlreverse('doc_writeup', kwargs=dict(name=doc.name))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(appr.text in unicontent(r))
|
||||
self.assertTrue(notes.text in unicontent(r))
|
||||
self.assertTrue(rfced_note.text in r.content)
|
||||
|
||||
def test_history(self):
|
||||
doc = make_test_data()
|
||||
|
|
|
@ -274,6 +274,45 @@ class BallotWriteupsTests(TestCase):
|
|||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text").text)
|
||||
|
||||
def test_edit_ballot_rfceditornote(self):
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_ballot_rfceditornote', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# add a note to the RFC Editor
|
||||
WriteupDocEvent.objects.create(
|
||||
doc=draft,
|
||||
desc="Changed text",
|
||||
type="changed_rfc_editor_note_text",
|
||||
text="This is a note for the RFC Editor.",
|
||||
by=Person.objects.get(name="(System)"))
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('textarea[name=rfc_editor_note]')), 1)
|
||||
self.assertTrue(q('[type=submit]:contains("Save")'))
|
||||
self.assertTrue("<label class=\"control-label\">RFC Editor Note</label>" in r.content)
|
||||
self.assertTrue("This is a note for the RFC Editor" in r.content)
|
||||
|
||||
# save with a note
|
||||
r = self.client.post(url, dict(
|
||||
rfc_editor_note="This is a simple test.",
|
||||
save_ballot_rfceditornote="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue(draft.has_rfc_editor_note())
|
||||
self.assertTrue("This is a simple test" in draft.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text").text)
|
||||
|
||||
# clear the existing note
|
||||
r = self.client.post(url, dict(
|
||||
rfc_editor_note=" ",
|
||||
clear_ballot_rfceditornote="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertFalse(draft.has_rfc_editor_note())
|
||||
|
||||
def test_issue_ballot(self):
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
|
||||
|
@ -341,6 +380,55 @@ class BallotWriteupsTests(TestCase):
|
|||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertTrue("Subject: Results of IETF-conflict review" in draft.latest_event(WriteupDocEvent, type="changed_ballot_approval_text").text)
|
||||
|
||||
def test_edit_verify_permissions(self):
|
||||
|
||||
def verify_fail(username, url):
|
||||
if username:
|
||||
self.client.login(username=username, password=username+"+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,403)
|
||||
|
||||
def verify_can_see(username, url):
|
||||
self.client.login(username=username, password=username+"+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q("<textarea class=\"form-control\"")),1)
|
||||
|
||||
draft = make_test_data()
|
||||
|
||||
e = WriteupDocEvent()
|
||||
e.type = "changed_ballot_approval_text"
|
||||
e.by = Person.objects.get(name="(System)")
|
||||
e.doc = draft
|
||||
e.desc = u"Ballot approval text was generated"
|
||||
e.text = u"Test approval text."
|
||||
e.save()
|
||||
|
||||
e = WriteupDocEvent()
|
||||
e.type = "changed_ballot_writeup_text"
|
||||
e.by = Person.objects.get(name="(System)")
|
||||
e.doc = draft
|
||||
e.desc = u"Ballot writeup was generated"
|
||||
e.text = u"Test ballot writeup text."
|
||||
e.save()
|
||||
|
||||
e = WriteupDocEvent()
|
||||
e.type = "changed_ballot_rfceditornote_text"
|
||||
e.by = Person.objects.get(name="(System)")
|
||||
e.doc = draft
|
||||
e.desc = u"RFC Editor Note for ballot was generated"
|
||||
e.text = u"Test note to the RFC Editor text."
|
||||
e.save()
|
||||
|
||||
for p in ['doc_ballot_approvaltext','doc_ballot_writeupnotes','doc_ballot_rfceditornote']:
|
||||
url = urlreverse(p, kwargs=dict(name=draft.name))
|
||||
|
||||
for username in ['plain','marschairman','iana','iab chair']:
|
||||
verify_fail(username, url)
|
||||
|
||||
for username in ['secretary','ad']:
|
||||
verify_can_see(username, url)
|
||||
|
||||
class ApproveBallotTests(TestCase):
|
||||
def test_approve_ballot(self):
|
||||
|
|
|
@ -100,6 +100,7 @@ urlpatterns = patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/undeferballot/$', views_ballot.undefer_ballot, name='doc_undefer_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/lastcalltext/$', views_ballot.lastcalltext, name='doc_ballot_lastcall'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ballotwriteupnotes/$', views_ballot.ballot_writeupnotes, name='doc_ballot_writeupnotes'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ballotrfceditornote/$', views_ballot.ballot_rfceditornote, name='doc_ballot_rfceditornote'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approvaltext/$', views_ballot.ballot_approvaltext, name='doc_ballot_approvaltext'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approveballot/$', views_ballot.approve_ballot, name='doc_approve_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/makelastcall/$', views_ballot.make_last_call, name='doc_make_last_call'),
|
||||
|
|
|
@ -19,7 +19,8 @@ from ietf.doc.utils import ( add_state_change_event, close_ballot, close_open_ba
|
|||
create_ballot_if_not_open, update_telechat )
|
||||
from ietf.doc.mails import ( email_ballot_deferred, email_ballot_undeferred,
|
||||
extra_automation_headers, generate_last_call_announcement,
|
||||
generate_issue_ballot_mail, generate_ballot_writeup, generate_approval_mail )
|
||||
generate_issue_ballot_mail, generate_ballot_writeup, generate_ballot_rfceditornote,
|
||||
generate_approval_mail )
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
from ietf.iesg.models import TelechatDate
|
||||
from ietf.ietfauth.utils import has_role, role_required
|
||||
|
@ -585,6 +586,57 @@ def ballot_writeupnotes(request, name):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class BallotRfcEditorNoteForm(forms.Form):
|
||||
rfc_editor_note = forms.CharField(widget=forms.Textarea, label="RFC Editor Note", required=True)
|
||||
|
||||
def clean_rfc_editor_note(self):
|
||||
return self.cleaned_data["rfc_editor_note"].replace("\r", "")
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def ballot_rfceditornote(request, name):
|
||||
"""Editing of RFC Editor Note in the ballot"""
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
|
||||
login = request.user.person
|
||||
|
||||
|
||||
|
||||
existing = doc.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
|
||||
if not existing or (existing.text == ""):
|
||||
existing = generate_ballot_rfceditornote(request, doc)
|
||||
|
||||
form = BallotRfcEditorNoteForm(auto_id=False, initial=dict(rfc_editor_note=existing.text))
|
||||
|
||||
if request.method == 'POST' and "save_ballot_rfceditornote" in request.POST:
|
||||
form = BallotRfcEditorNoteForm(request.POST)
|
||||
if form.is_valid():
|
||||
t = form.cleaned_data["rfc_editor_note"]
|
||||
if t != existing.text:
|
||||
e = WriteupDocEvent(doc=doc, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_rfc_editor_note_text"
|
||||
e.desc = "RFC Editor Note was changed"
|
||||
e.text = t.rstrip()
|
||||
e.save()
|
||||
|
||||
if request.method == 'POST' and "clear_ballot_rfceditornote" in request.POST:
|
||||
e = WriteupDocEvent(doc=doc, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_rfc_editor_note_text"
|
||||
e.desc = "RFC Editor Note was cleared"
|
||||
e.text = ""
|
||||
e.save()
|
||||
|
||||
# make sure form shows a blank RFC Editor Note
|
||||
form = BallotRfcEditorNoteForm(initial=dict(rfc_editor_note=" "))
|
||||
|
||||
return render_to_response('doc/ballot/rfceditornote.html',
|
||||
dict(doc=doc,
|
||||
back_url=doc.get_absolute_url(),
|
||||
ballot_rfceditornote_form=form,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class ApprovalTextForm(forms.Form):
|
||||
approval_text = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
||||
|
@ -657,7 +709,19 @@ def approve_ballot(request, name):
|
|||
if not e:
|
||||
e = generate_ballot_writeup(request, doc)
|
||||
ballot_writeup = e.text
|
||||
|
||||
|
||||
error_duplicate_rfc_editor_note = False
|
||||
e = doc.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
|
||||
if e and (e.text != ""):
|
||||
if "RFC Editor Note" in ballot_writeup:
|
||||
error_duplicate_rfc_editor_note = True
|
||||
ballot_writeup += "\n\n" + e.text
|
||||
|
||||
if error_duplicate_rfc_editor_note:
|
||||
return render_to_response('doc/draft/rfceditor_note_duplicate_error.html',
|
||||
dict(doc=doc),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
if "NOT be published" in approval_text:
|
||||
action = "do_not_publish"
|
||||
elif "To: RFC Editor" in approval_text:
|
||||
|
|
|
@ -735,6 +735,10 @@ def document_writeup(request, name):
|
|||
text_from_writeup("changed_ballot_writeup_text"),
|
||||
urlreverse("doc_ballot_writeupnotes", kwargs=dict(name=doc.name))))
|
||||
|
||||
writeups.append(("RFC Editor Note",
|
||||
text_from_writeup("changed_rfc_editor_note_text"),
|
||||
urlreverse("doc_ballot_rfceditornote", kwargs=dict(name=doc.name))))
|
||||
|
||||
elif doc.type_id == "charter":
|
||||
sections.append(("WG Review Announcement",
|
||||
"",
|
||||
|
|
|
@ -160,6 +160,9 @@ def agenda_json(request, date=None):
|
|||
e = doc.latest_event(ConsensusDocEvent, type="changed_consensus")
|
||||
if e:
|
||||
docinfo['consensus'] = e.consensus
|
||||
|
||||
docinfo['rfc-ed-note'] = doc.has_rfc_editor_note()
|
||||
|
||||
elif doc.type_id == 'conflrev':
|
||||
docinfo['rev'] = doc.rev
|
||||
td = doc.relateddocument_set.get(relationship__slug='conflrev').target.document
|
||||
|
|
|
@ -57,7 +57,14 @@ def get_doc_writeup(doc):
|
|||
want to display the contents of the document
|
||||
'''
|
||||
writeup = 'This document has no writeup'
|
||||
if doc.type_id in ('draft','charter'):
|
||||
if doc.type_id == 'draft':
|
||||
latest = doc.latest_event(WriteupDocEvent, type='changed_ballot_writeup_text')
|
||||
if latest and doc.has_rfc_editor_note:
|
||||
rfced_note = doc.latest_event(WriteupDocEvent, type="changed_rfc_editor_note_text")
|
||||
writeup = latest.text + "\n\n" + rfced_note.text
|
||||
else:
|
||||
writeup = latest.text
|
||||
if doc.type_id == 'charter':
|
||||
latest = doc.latest_event(WriteupDocEvent, type='changed_ballot_writeup_text')
|
||||
if latest:
|
||||
writeup = latest.text
|
||||
|
|
30
ietf/templates/doc/ballot/rfceditornote.html
Normal file
30
ietf/templates/doc/ballot/rfceditornote.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2016, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}RFC Editor Note for ballot for {{ doc }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
|
||||
<h1>RFC Editor Note for ballot<br><small><a href="{% url "doc_view" name=doc.canonical_name %}">{{ doc }}</a></small></h1>
|
||||
|
||||
{% bootstrap_messages %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form ballot_rfceditornote_form %}
|
||||
|
||||
<div class="help-block">
|
||||
RFC Editor Note. This text will be appended to all announcements and messages to the RFC Editor.
|
||||
</div>
|
||||
|
||||
{% buttons %}
|
||||
<button type="submit" class="btn btn-primary" name="save_ballot_rfceditornote" value="Save Ballot RFC Editor Note">Save</button>
|
||||
<button type="submit" class="btn btn-warning" name="clear_ballot_rfceditornote" value="Clear Ballot RFC Editor Note">Clear</button>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
{% endblock%}
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{# Copyright The IETF Trust 2016, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
|
@ -18,7 +18,7 @@
|
|||
{% bootstrap_form ballot_writeup_form %}
|
||||
|
||||
<div class="help-block">
|
||||
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.
|
||||
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.
|
||||
</div>
|
||||
|
||||
{% buttons %}
|
||||
|
|
18
ietf/templates/doc/draft/rfceditor_note_duplicate_error.html
Normal file
18
ietf/templates/doc/draft/rfceditor_note_duplicate_error.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2016, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% block title %}Duplicate RFC Editor Note Error{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>There appear to be two RFC Editor Notes for this approved I-D</h1>
|
||||
|
||||
<p>Sorry, there appears to be an RFC Editor Note in the ballot writeup and
|
||||
another one in the RFC Editor Note. Please put all of the information for
|
||||
the RFC Editor in the RFC Editor Note.</p>
|
||||
|
||||
<p>The document writeup can be edited
|
||||
<a href="{% url "doc_view" name=doc.canonical_name %}writeup/"> <em>Here</em></a>.</p>
|
||||
|
||||
{% endblock %}
|
5
ietf/templates/doc/mail/ballot_rfceditornote.txt
Normal file
5
ietf/templates/doc/mail/ballot_rfceditornote.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
{% autoescape off %}
|
||||
RFC Editor Note
|
||||
|
||||
(Insert RFC Editor Note here or remove section)
|
||||
{% endautoescape%}
|
|
@ -32,10 +32,6 @@ Personnel
|
|||
experts(s), insert 'The IANA Expert(s) for the registries
|
||||
in this document are <TO BE ADDED BY THE AD>.'
|
||||
|
||||
RFC Editor Note
|
||||
|
||||
(Insert RFC Editor Note here or remove section)
|
||||
|
||||
IRTF Note
|
||||
|
||||
(Insert IRTF Note here or remove section)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{# Copyright The IETF Trust 2015, All Rights Reserved #}{% load origin %}{% origin %}
|
||||
{# Copyright The IETF Trust 2016, All Rights Reserved #}{% load origin %}{% origin %}
|
||||
{% load ietf_filters ballot_icon %}
|
||||
|
||||
<div class="pull-right">{% ballot_icon doc %}</div>
|
||||
|
@ -20,6 +20,9 @@
|
|||
<span class="fa fa-file"></span></a>
|
||||
{% endwith %}
|
||||
<a href="{% url "doc_view" name=doc.canonical_name %}">{{ doc.canonical_name }}</a>
|
||||
{% if doc.has_rfc_editor_note %}
|
||||
<a href="{% url "doc_view" name=doc.canonical_name %}writeup/"> <em>(Has RFC Editor Note)</em></a>
|
||||
{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt>{{ doc.intended_std_level }}</dt><dd><b>{{ doc.title }}</b></dd>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% load ietf_filters %}{% with doc.rfc_number as rfc_number %}
|
||||
o {{doc.canonical_name}}{% if not rfc_number %}-{{doc.rev}}{% endif %}{% endwith %}{% if doc.stream %} - {{ doc.stream }} stream{% endif %}
|
||||
o {{doc.canonical_name}}{% if not rfc_number %}-{{doc.rev}}{% endif %}{% endwith %}{%if doc.has_rfc_editor_note %} (Has RFC Editor Note){% endif %}{% if doc.stream %} - {{ doc.stream }} stream{% endif %}
|
||||
{% filter wordwrap:"68"|indent|indent %}{{ doc.title }} ({{ doc.intended_std_level }}){% endfilter %}
|
||||
{% if doc.note %}{# note: note is not escaped #} {% filter wordwrap:"68"|indent|indent %}Note: {{ doc.note|striptags }}{% endfilter %}
|
||||
{% endif %} Token: {{ doc.ad }}{% if doc.iana_review_state %}
|
||||
|
|
Loading…
Reference in a new issue