diff --git a/ietf/idrfc/testsREDESIGN.py b/ietf/idrfc/testsREDESIGN.py index f35d1a793..4b136c666 100644 --- a/ietf/idrfc/testsREDESIGN.py +++ b/ietf/idrfc/testsREDESIGN.py @@ -882,13 +882,13 @@ class ApproveBallotTestCase(django.test.TestCase): r = self.client.get(url) self.assertEquals(r.status_code, 200) q = PyQuery(r.content) - self.assertTrue("Send out the announcement" in q('.actions input[type=submit]')[0].get('value')) + self.assertTrue("send out the announcement" in q('.actions input[type=submit]')[0].get('value').lower()) self.assertEquals(len(q('.announcement pre:contains("Subject: Protocol Action")')), 1) # approve mailbox_before = len(outbox) - r = self.client.post(url, dict()) + r = self.client.post(url, dict(skiprfceditorpost="1")) self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) @@ -897,6 +897,7 @@ class ApproveBallotTestCase(django.test.TestCase): self.assertTrue("Protocol Action" in outbox[-2]['Subject']) # the IANA copy self.assertTrue("Protocol Action" in outbox[-1]['Subject']) + self.assertTrue(not outbox[-1]['CC']) self.assertTrue("Protocol Action" in draft.message_set.order_by("-time")[0].subject) def test_disapprove_ballot(self): @@ -981,7 +982,7 @@ class RequestPublicationTestCase(django.test.TestCase): # approve mailbox_before = len(outbox) - r = self.client.post(url, dict(subject=subject, body=body)) + r = self.client.post(url, dict(subject=subject, body=body, skiprfceditorpost="1")) self.assertEquals(r.status_code, 302) draft = Document.objects.get(name=draft.name) @@ -991,6 +992,7 @@ class RequestPublicationTestCase(django.test.TestCase): self.assertTrue("Document Action" in draft.message_set.order_by("-time")[0].subject) # the IANA copy self.assertTrue("Document Action" in outbox[-1]['Subject']) + self.assertTrue(not outbox[-1]['CC']) class ExpireIDsTestCase(django.test.TestCase): fixtures = ['names'] diff --git a/ietf/idrfc/views_ballot.py b/ietf/idrfc/views_ballot.py index b2b1bba82..f7d16e652 100644 --- a/ietf/idrfc/views_ballot.py +++ b/ietf/idrfc/views_ballot.py @@ -1008,7 +1008,7 @@ def approve_ballotREDESIGN(request, name): # NOTE: according to Michelle Cotton # (as per 2011-10-24) IANA is scraping these messages for # information so would like to know beforehand if the format - # changes (perhaps RFC 6359 will change that) + # changes announcement = approval_text + "\n\n" + ballot_writeup if request.method == 'POST': @@ -1017,6 +1017,17 @@ def approve_ballotREDESIGN(request, name): else: new_state = State.objects.get(used=True, type="draft-iesg", slug="ann") + if new_state.slug == "ann" and not request.REQUEST.get("skiprfceditorpost"): + # start by notifying the RFC Editor + import ietf.sync.rfceditor + response, error = ietf.sync.rfceditor.post_approved_draft(ietf.sync.rfceditor.POST_APPROVED_DRAFT_URL, doc.name) + if error: + return render_to_response('doc/rfceditor_post_approved_draft_failed.html', + dict(name=doc.name, + response=response, + error=error), + context_instance=RequestContext(request)) + # fixup document close_open_ballots(doc, login) @@ -1064,7 +1075,7 @@ def approve_ballotREDESIGN(request, name): msg.related_docs.add(doc) return HttpResponseRedirect(doc.get_absolute_url()) - + return render_to_response('idrfc/approve_ballot.html', dict(doc=doc, action=action, diff --git a/ietf/idrfc/views_edit.py b/ietf/idrfc/views_edit.py index 7759b100b..f096daaf4 100644 --- a/ietf/idrfc/views_edit.py +++ b/ietf/idrfc/views_edit.py @@ -1088,6 +1088,17 @@ def request_publication(request, name): if request.method == 'POST' and not request.POST.get("reset"): form = PublicationForm(request.POST) if form.is_valid(): + if not request.REQUEST.get("skiprfceditorpost"): + # start by notifying the RFC Editor + import ietf.sync.rfceditor + response, error = ietf.sync.rfceditor.post_approved_draft(ietf.sync.rfceditor.POST_APPROVED_DRAFT_URL, doc.name) + if error: + return render_to_response('doc/rfceditor_post_approved_draft_failed.html', + dict(name=doc.name, + response=response, + error=error), + context_instance=RequestContext(request)) + m.subject = form.cleaned_data["subject"] m.body = form.cleaned_data["body"] m.save() diff --git a/ietf/settings.py b/ietf/settings.py index f92340fa2..f22f23210 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -277,6 +277,8 @@ IANA_SYNC_PASSWORD = "secret" IANA_SYNC_CHANGES_URL = "https://datatracker.iana.org:4443/data-tracker/changes" IANA_SYNC_PROTOCOLS_URL = "http://www.iana.org/protocols/" +RFC_EDITOR_SYNC_PASSWORD="secret" + # Liaison Statement Tool settings LIAISON_UNIVERSAL_FROM = 'Liaison Statement Management Tool ' LIAISON_ATTACH_PATH = '/a/www/ietf-datatracker/documents/LIAISON/' diff --git a/ietf/sync/rfceditor.py b/ietf/sync/rfceditor.py index 2acd7c627..241751bce 100644 --- a/ietf/sync/rfceditor.py +++ b/ietf/sync/rfceditor.py @@ -1,4 +1,4 @@ -import re, urllib2, json, email, socket +import re, urllib, urllib2, json, email, socket, base64 from xml.dom import pulldom, Node from django.utils.http import urlquote @@ -12,6 +12,7 @@ from ietf.doc.utils import add_state_change_event QUEUE_URL = "http://www.rfc-editor.org/queue2.xml" INDEX_URL = "http://www.rfc-editor.org/rfc/rfc-index.xml" +POST_APPROVED_DRAFT_URL = "https://www.rfc-editor.org/sdev/jsonexp/jsonparser.php" MIN_QUEUE_RESULTS = 10 MIN_INDEX_RESULTS = 5000 @@ -445,3 +446,37 @@ def update_docs_from_rfc_index(data, skip_older_than_date=None): doc.save() return results + + +def post_approved_draft(url, name): + """Post an approved draft to the RFC Editor so they can retrieve + the data from the Datatracker and start processing it. Returns + response and error (empty string if no error).""" + + request = urllib2.Request(url) + request.add_header("Content-type", "application/x-www-form-urlencoded") + request.add_header("Accept", "text/plain") + # HTTP basic auth + username = "dtracksync" + password = settings.RFC_EDITOR_SYNC_PASSWORD + request.add_header("Authorization", "Basic %s" % base64.encodestring("%s:%s" % (username, password)).replace("\n", "")) + + text = error = "" + try: + f = urllib2.urlopen(request, data=urllib.urlencode({ 'approved_draft_name': name }), timeout=20) + text = f.read() + status_code = f.getcode() + f.close() + + if status_code != 200: + raise Exception("Status code is not 200 OK (it's %s)." % status_code) + + if text != "OK": + raise Exception("Response is not \"OK\".") + + except Exception as e: + # catch everything so we don't leak exceptions, convert them + # into string instead + error = unicode(e) + + return text, error diff --git a/ietf/templates/doc/rfceditor_post_approved_draft_failed.html b/ietf/templates/doc/rfceditor_post_approved_draft_failed.html new file mode 100644 index 000000000..d27cd3ed7 --- /dev/null +++ b/ietf/templates/doc/rfceditor_post_approved_draft_failed.html @@ -0,0 +1,26 @@ +{# Copyright The IETF Trust 2007, All Rights Reserved #} +{% extends "base.html" %} + +{% block title %}Posting Approved Draft to RFC Editor Failed{% endblock %} + +{% block content %} +

Posting Approved Draft to RFC Editor Failed

+ +

Sorry, when trying to notify the RFC Editor through HTTP, we hit an +error.

+ +

We have not changed the draft state or sent the announcement +yet so if this is an intermittent error, you can go back and try +again.

+ +

The error was:

+ +

{{ error }}

+ +{% if response %} +

The response from the RFC Editor was:

+ +

{{ response|linebreaksbr }}

+{% endif %} + +{% endblock %} diff --git a/ietf/templates/idrfc/approve_ballot.html b/ietf/templates/idrfc/approve_ballot.html index f7a4c8ef1..a451d2230 100644 --- a/ietf/templates/idrfc/approve_ballot.html +++ b/ietf/templates/idrfc/approve_ballot.html @@ -32,7 +32,7 @@ form.approve-ballot .announcement {
Back {% ifequal action "to_announcement_list" %} - + {% endifequal %} {% ifequal action "to_rfc_editor" %}