Add POST interface for IANA/RFC Editor for triggering updates, add
discrepancies report for seeing differences between the Datatracker/RFC Editor/IANA, add tests of IANA/RFC Editor integration, add script for weekly discrepancies emails - Legacy-Id: 4851
This commit is contained in:
parent
5282bd1d07
commit
85d2cdddc2
35
ietf/bin/email-sync-discrepancies
Executable file
35
ietf/bin/email-sync-discrepancies
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
import syslog
|
||||
|
||||
# boilerplate
|
||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
||||
sys.path = [ basedir ] + sys.path
|
||||
|
||||
from ietf import settings
|
||||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
|
||||
from optparse import OptionParser
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("-t", "--to", dest="to",
|
||||
help="Email address to send report to", metavar="EMAIL")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
|
||||
syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
|
||||
|
||||
from ietf.sync.mails import email_discrepancies
|
||||
|
||||
receivers = ["iesg-secretary@ietf.org"]
|
||||
|
||||
if options.to:
|
||||
receivers = [options.to]
|
||||
|
||||
email_discrepancies(receivers)
|
||||
|
||||
syslog.syslog("Emailed sync discrepancies to %s" % receivers)
|
37
ietf/sync/discrepancies.py
Normal file
37
ietf/sync/discrepancies.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
from ietf.doc.models import *
|
||||
|
||||
def find_discrepancies():
|
||||
res = []
|
||||
|
||||
title = "Drafts that have been sent to the RFC Editor but do not have an RFC Editor state"
|
||||
|
||||
docs = Document.objects.filter(states__in=list(State.objects.filter(type="draft-iesg", slug__in=("ann", "rfcqueue")))).exclude(states__in=list(State.objects.filter(type="draft-rfceditor")))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
title = "Drafts that have the IANA Action state \"In Progress\" but do not have a \"IANA\" RFC-Editor state/tag"
|
||||
|
||||
docs = Document.objects.filter(states__in=list(State.objects.filter(type="draft-iana-action", slug__in=("inprog",)))).exclude(tags="iana").exclude(states__in=list(State.objects.filter(type="draft-rfceditor", slug="iana")))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
title = "Drafts that have the IANA Action state \"Waiting on RFC Editor\" or \"RFC-Ed-Ack\" but are in the RFC Editor state \"IANA\"/tagged with \"IANA\""
|
||||
|
||||
docs = Document.objects.filter(states__in=list(State.objects.filter(type="draft-iana-action", slug__in=("waitrfc", "rfcedack")))).filter(models.Q(tags="iana") | models.Q(states__in=list(State.objects.filter(type="draft-rfceditor", slug="iana"))))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
title = "Drafts that have a state other than \"RFC Ed Queue\", \"RFC Published\" or \"Sent to the RFC Editor\" and have an RFC Editor or IANA Action state"
|
||||
|
||||
docs = Document.objects.exclude(states__in=list(State.objects.filter(type="draft-iesg", slug__in=("rfcqueue", "pub"))) + list(State.objects.filter(type__in=("draft-stream-iab", "draft-stream-ise", "draft-stream-irtf"), slug="rfc-edit"))).filter(states__in=list(State.objects.filter(type__in=("draft-iana-action", "draft-rfceditor"))))
|
||||
|
||||
res.append((title, docs))
|
||||
|
||||
for _, docs in res:
|
||||
for d in docs:
|
||||
d.iesg_state = d.get_state("draft-iesg")
|
||||
d.rfc_state = d.get_state("draft-rfceditor")
|
||||
d.iana_action_state = d.get_state("draft-iana-action")
|
||||
|
||||
return res
|
||||
|
21
ietf/sync/mails.py
Normal file
21
ietf/sync/mails.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.utils.mail import send_mail
|
||||
|
||||
from ietf.sync.discrepancies import find_discrepancies
|
||||
|
||||
def email_discrepancies(receivers):
|
||||
sections = find_discrepancies()
|
||||
|
||||
send_mail(None,
|
||||
receivers,
|
||||
None,
|
||||
"Datatracker Sync Discrepancies Report",
|
||||
"sync/discrepancies_report.txt",
|
||||
dict(sections=sections,
|
||||
url=settings.IDTRACKER_BASE_URL + urlreverse("ietf.sync.views.discrepancies"),
|
||||
base_url=settings.IDTRACKER_BASE_URL,
|
||||
))
|
||||
|
||||
|
401
ietf/sync/tests.py
Normal file
401
ietf/sync/tests.py
Normal file
|
@ -0,0 +1,401 @@
|
|||
import unittest, re, json, datetime, StringIO
|
||||
import django.test
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.utils.mail import outbox
|
||||
from ietf.utils.test_data import make_test_data
|
||||
from ietf.utils.test_utils import login_testing_unauthorized
|
||||
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import *
|
||||
|
||||
from ietf.sync import iana, rfceditor
|
||||
|
||||
from pyquery import PyQuery
|
||||
|
||||
class IANASyncTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_protocol_page_sync(self):
|
||||
draft = make_test_data()
|
||||
DocAlias.objects.create(name="rfc1234", document=draft)
|
||||
DocEvent.objects.create(doc=draft, type="published_rfc", by=Person.objects.get(name="(System)"))
|
||||
|
||||
rfc_names = iana.parse_protocol_page('<html><a href="/go/rfc1234/">RFC 1234</a></html>')
|
||||
self.assertEqual(len(rfc_names), 1)
|
||||
self.assertEqual(rfc_names[0], "rfc1234")
|
||||
|
||||
iana.update_rfc_log_from_protocol_page(rfc_names, datetime.datetime.now() - datetime.timedelta(days=1))
|
||||
self.assertEqual(DocEvent.objects.filter(doc=draft, type="rfc_in_iana_registry").count(), 1)
|
||||
|
||||
# make sure it doesn't create duplicates
|
||||
iana.update_rfc_log_from_protocol_page(rfc_names, datetime.datetime.now() - datetime.timedelta(days=1))
|
||||
self.assertEqual(DocEvent.objects.filter(doc=draft, type="rfc_in_iana_registry").count(), 1)
|
||||
|
||||
def test_changes_sync(self):
|
||||
draft = make_test_data()
|
||||
|
||||
data = json.dumps({
|
||||
"changes": [
|
||||
{
|
||||
"time": "2011-10-09 12:00:01",
|
||||
"doc": draft.name,
|
||||
"state": "IANA Not OK",
|
||||
"type": "iana_review",
|
||||
},
|
||||
{
|
||||
"time": "2011-10-09 12:00:00",
|
||||
"doc": draft.name,
|
||||
"state": "Waiting on RFC-Editor",
|
||||
"type": "iana_state",
|
||||
},
|
||||
{
|
||||
"time": "2011-10-09 11:00:00",
|
||||
"doc": draft.name,
|
||||
"state": "In Progress",
|
||||
"type": "iana_state",
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
changes = iana.parse_changes_json(data)
|
||||
# check sorting
|
||||
self.assertEqual(changes[0]["time"], "2011-10-09 11:00:00")
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
added_events, warnings = iana.update_history_with_changes(changes)
|
||||
|
||||
self.assertEqual(len(added_events), 3)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
self.assertEqual(draft.get_state_slug("draft-iana-review"), "not-ok")
|
||||
self.assertEqual(draft.get_state_slug("draft-iana-action"), "waitrfc")
|
||||
e = draft.latest_event(StateDocEvent, type="changed_state", state_type="draft-iana-action")
|
||||
self.assertEqual(e.desc, "IANA Action state changed to <b>Waiting on RFC Editor</b> from In Progress")
|
||||
self.assertEqual(e.time, datetime.datetime(2011, 10, 9, 5, 0)) # check timezone handling
|
||||
self.assertEqual(len(outbox), mailbox_before + 3 * 2)
|
||||
|
||||
# make sure it doesn't create duplicates
|
||||
added_events, warnings = iana.update_history_with_changes(changes)
|
||||
self.assertEqual(len(added_events), 0)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
|
||||
def test_changes_sync_errors(self):
|
||||
draft = make_test_data()
|
||||
|
||||
# missing "type"
|
||||
data = json.dumps({
|
||||
"changes": [
|
||||
{
|
||||
"time": "2011-10-09 12:00:01",
|
||||
"doc": draft.name,
|
||||
"state": "IANA Not OK",
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
self.assertRaises(Exception, iana.parse_changes_json, data)
|
||||
|
||||
# error response
|
||||
data = json.dumps({
|
||||
"error": "I am in error."
|
||||
})
|
||||
|
||||
self.assertRaises(Exception, iana.parse_changes_json, data)
|
||||
|
||||
# missing document from database
|
||||
data = json.dumps({
|
||||
"changes": [
|
||||
{
|
||||
"time": "2011-10-09 12:00:01",
|
||||
"doc": "draft-this-does-not-exist",
|
||||
"state": "IANA Not OK",
|
||||
"type": "iana_review",
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
changes = iana.parse_changes_json(data)
|
||||
added_events, warnings = iana.update_history_with_changes(changes)
|
||||
self.assertEqual(len(added_events), 0)
|
||||
self.assertEqual(len(warnings), 1)
|
||||
|
||||
def test_iana_review_mail(self):
|
||||
draft = make_test_data()
|
||||
|
||||
msg = """From: "%(person)s via RT" <drafts-lastcall@iana.org>
|
||||
Date: Thu, 10 May 2012 12:00:00 +0000
|
||||
Subject: [IANA #12345] Last Call: <%(draft)s-%(rev)s.txt> (Long text) to Informational RFC
|
||||
(BEGIN IANA LAST CALL COMMENTS)
|
||||
|
||||
IESG:
|
||||
|
||||
IANA has reviewed %(draft)s-%(rev)s, which is=20
|
||||
currently in Last Call, and has the following comments:
|
||||
|
||||
IANA understands that, upon approval of this document, there are no=20
|
||||
IANA Actions that need completion.
|
||||
|
||||
Thanks,
|
||||
|
||||
%(person)s
|
||||
IANA Fake Test Person
|
||||
ICANN
|
||||
|
||||
(END IANA LAST CALL COMMENTS)
|
||||
"""
|
||||
|
||||
msg = msg % dict(person=Person.objects.get(user__username="iana").name,
|
||||
draft=draft.name,
|
||||
rev=draft.rev)
|
||||
|
||||
doc_name, review_time, by, comment = iana.parse_review_email(msg)
|
||||
|
||||
self.assertEqual(doc_name, draft.name)
|
||||
self.assertEqual(review_time, datetime.datetime(2012, 5, 10, 5, 0, 0))
|
||||
self.assertEqual(by, Person.objects.get(user__username="iana"))
|
||||
self.assertTrue("there are no IANA Actions" in comment.replace("\n", ""))
|
||||
|
||||
iana.add_review_comment(doc_name, review_time, by, comment)
|
||||
|
||||
e = draft.latest_event(type="iana_review")
|
||||
self.assertTrue(e)
|
||||
self.assertEqual(e.desc, comment)
|
||||
self.assertEqual(e.by, by)
|
||||
|
||||
# make sure it doesn't create duplicates
|
||||
iana.add_review_comment(doc_name, review_time, by, comment)
|
||||
self.assertEqual(DocEvent.objects.filter(doc=draft, type="iana_review").count(), 1)
|
||||
|
||||
|
||||
class RFCSyncTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_rfc_index(self):
|
||||
doc = make_test_data()
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="rfcqueue"))
|
||||
# it's a bit strange to have this set when draft-iesg is set
|
||||
# too, but for testing purposes ...
|
||||
doc.set_state(State.objects.get(type="draft-stream-ise", slug="rfc-edit"))
|
||||
|
||||
updated_doc = Document.objects.create(name="draft-ietf-something")
|
||||
DocAlias.objects.create(name=updated_doc.name, document=updated_doc)
|
||||
DocAlias.objects.create(name="rfc123", document=updated_doc)
|
||||
|
||||
today = datetime.date.today()
|
||||
|
||||
t = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rfc-index xmlns="http://www.rfc-editor.org/rfc-index"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.rfc-editor.org/rfc-index
|
||||
http://www.rfc-editor.org/rfc-index.xsd">
|
||||
<bcp-entry>
|
||||
<doc-id>BCP0001</doc-id>
|
||||
<is-also>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
<doc-id>RFC2345</doc-id>
|
||||
</is-also>
|
||||
</bcp-entry>
|
||||
<fyi-entry>
|
||||
<doc-id>FYI0001</doc-id>
|
||||
<is-also>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
</is-also>
|
||||
</fyi-entry>
|
||||
<std-entry>
|
||||
<doc-id>STD0001</doc-id>
|
||||
<title>Test</title>
|
||||
<is-also>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
</is-also>
|
||||
</std-entry>
|
||||
<rfc-entry>
|
||||
<doc-id>RFC1234</doc-id>
|
||||
<title>A Testing RFC</title>
|
||||
<author>
|
||||
<name>A. Irector</name>
|
||||
</author>
|
||||
<date>
|
||||
<month>%(month)s</month>
|
||||
<year>%(year)s</year>
|
||||
</date>
|
||||
<format>
|
||||
<file-format>ASCII</file-format>
|
||||
<char-count>12345</char-count>
|
||||
<page-count>42</page-count>
|
||||
</format>
|
||||
<keywords>
|
||||
<kw>test</kw>
|
||||
</keywords>
|
||||
<abstract><p>This is some interesting text.</p></abstract>
|
||||
<draft>%(name)s-%(rev)s</draft>
|
||||
<updates>
|
||||
<doc-id>RFC123</doc-id>
|
||||
</updates>
|
||||
<is-also>
|
||||
<doc-id>BCP0001</doc-id>
|
||||
</is-also>
|
||||
<current-status>PROPOSED STANDARD</current-status>
|
||||
<publication-status>PROPOSED STANDARD</publication-status>
|
||||
<stream>IETF</stream>
|
||||
<area>%(area)s</area>
|
||||
<wg_acronym>%(group)s</wg_acronym>
|
||||
<errata-url>http://www.rfc-editor.org/errata_search.php?rfc=1234</errata-url>
|
||||
</rfc-entry>
|
||||
</rfc-index>''' % dict(year=today.strftime("%Y"),
|
||||
month=today.strftime("%B"),
|
||||
name=doc.name,
|
||||
rev=doc.rev,
|
||||
area=doc.group.parent.acronym,
|
||||
group=doc.group.acronym)
|
||||
|
||||
data = rfceditor.parse_index(StringIO.StringIO(t))
|
||||
self.assertEqual(len(data), 1)
|
||||
|
||||
rfc_number, title, authors, rfc_published_date, current_status, updates, updated_by, obsoletes, obsoleted_by, also, draft, has_errata, stream, wg, file_formats, pages, abstract = data[0]
|
||||
|
||||
# currently, we only check what we actually use
|
||||
self.assertEqual(rfc_number, 1234)
|
||||
self.assertEqual(title, "A Testing RFC")
|
||||
self.assertEqual(rfc_published_date.year, today.year)
|
||||
self.assertEqual(rfc_published_date.month, today.month)
|
||||
self.assertEqual(current_status, "Proposed Standard")
|
||||
self.assertEqual(updates, ["RFC123"])
|
||||
self.assertEqual(set(also), set(["BCP0001", "FYI0001", "STD0001"]))
|
||||
self.assertEqual(draft, doc.name)
|
||||
self.assertEqual(wg, doc.group.acronym)
|
||||
self.assertEqual(has_errata, True)
|
||||
self.assertEqual(stream, "IETF")
|
||||
self.assertEqual(pages, "42")
|
||||
self.assertEqual(abstract, "This is some interesting text.")
|
||||
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
changed = rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30))
|
||||
|
||||
doc = Document.objects.get(name=doc.name)
|
||||
|
||||
self.assertEqual(doc.docevent_set.all()[0].type, "published_rfc")
|
||||
self.assertEqual(doc.docevent_set.all()[0].time.date(), today)
|
||||
self.assertTrue("errata" in doc.tags.all().values_list("slug", flat=True))
|
||||
self.assertTrue(DocAlias.objects.filter(name="rfc1234", document=doc))
|
||||
self.assertTrue(DocAlias.objects.filter(name="bcp0001", document=doc))
|
||||
self.assertTrue(DocAlias.objects.filter(name="fyi0001", document=doc))
|
||||
self.assertTrue(DocAlias.objects.filter(name="std0001", document=doc))
|
||||
self.assertTrue(RelatedDocument.objects.filter(source=doc, target__name="rfc123", relationship="updates"))
|
||||
self.assertEqual(doc.title, "A Testing RFC")
|
||||
self.assertEqual(doc.abstract, "This is some interesting text.")
|
||||
self.assertEqual(doc.get_state_slug(), "rfc")
|
||||
self.assertEqual(doc.get_state_slug("draft-iesg"), "pub")
|
||||
self.assertEqual(doc.get_state_slug("draft-stream-ise"), "pub")
|
||||
self.assertEqual(doc.std_level_id, "ps")
|
||||
self.assertEqual(doc.pages, 42)
|
||||
|
||||
# make sure we can apply it again with no changes
|
||||
changed = rfceditor.update_docs_from_rfc_index(data, today - datetime.timedelta(days=30))
|
||||
self.assertEquals(len(changed), 0)
|
||||
|
||||
|
||||
def test_rfc_queue(self):
|
||||
draft = make_test_data()
|
||||
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="ann"))
|
||||
|
||||
t = '''<rfc-editor-queue xmlns="http://www.rfc-editor.org/rfc-editor-queue">
|
||||
<section name="IETF STREAM: WORKING GROUP STANDARDS TRACK">
|
||||
<entry xml:id="%(name)s">
|
||||
<draft>%(name)s-%(rev)s.txt</draft>
|
||||
<date-received>2010-09-08</date-received>
|
||||
<state>EDIT*R*A(1G)</state>
|
||||
<auth48-url>http://www.rfc-editor.org/auth48/rfc1234</auth48-url>
|
||||
<normRef>
|
||||
<ref-name>%(ref)s</ref-name>
|
||||
<ref-state>IN-QUEUE</ref-state>
|
||||
</normRef>
|
||||
<authors>A. Author</authors>
|
||||
<title>
|
||||
%(title)s
|
||||
</title>
|
||||
<bytes>10000000</bytes>
|
||||
<source>%(group)s</source>
|
||||
</entry>
|
||||
</section>
|
||||
</rfc-editor-queue>''' % dict(name=draft.name,
|
||||
rev=draft.rev,
|
||||
title=draft.title,
|
||||
group=draft.group.name,
|
||||
ref="draft-ietf-test")
|
||||
|
||||
drafts, warnings = rfceditor.parse_queue(StringIO.StringIO(t))
|
||||
self.assertEqual(len(drafts), 1)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
|
||||
draft_name, date_received, state, tags, missref_generation, stream, auth48, cluster, refs = drafts[0]
|
||||
|
||||
# currently, we only check what we actually use
|
||||
self.assertEqual(draft_name, draft.name)
|
||||
self.assertEqual(state, "EDIT")
|
||||
self.assertEqual(set(tags), set(["iana", "ref"]))
|
||||
self.assertEqual(auth48, "http://www.rfc-editor.org/auth48/rfc1234")
|
||||
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
changed, warnings = rfceditor.update_drafts_from_queue(drafts)
|
||||
self.assertEqual(len(changed), 1)
|
||||
self.assertEqual(len(warnings), 0)
|
||||
|
||||
self.assertEqual(draft.get_state_slug("draft-rfceditor"), "edit")
|
||||
self.assertEqual(set(draft.tags.all()), set(DocTagName.objects.filter(slug__in=("iana", "ref"))))
|
||||
self.assertEqual(draft.docevent_set.all()[0].type, "changed_state")
|
||||
self.assertEqual(draft.docevent_set.all()[1].type, "rfc_editor_received_announcement")
|
||||
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("RFC Editor queue" in outbox[-1]["Subject"])
|
||||
|
||||
# make sure we can apply it again with no changes
|
||||
changed, warnings = rfceditor.update_drafts_from_queue(drafts)
|
||||
self.assertEquals(len(changed), 0)
|
||||
self.assertEquals(len(warnings), 0)
|
||||
|
||||
class DiscrepanciesTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_discrepancies(self):
|
||||
make_test_data()
|
||||
|
||||
# draft approved but no RFC Editor state
|
||||
doc = Document.objects.create(name="draft-ietf-test1", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="ann"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
||||
|
||||
# draft with IANA state "In Progress" but RFC Editor state not IANA
|
||||
doc = Document.objects.create(name="draft-ietf-test2", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="rfcqueue"))
|
||||
doc.set_state(State.objects.get(type="draft-iana-action", slug="inprog"))
|
||||
doc.set_state(State.objects.get(type="draft-rfceditor", slug="auth"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
||||
|
||||
# draft with IANA state "Waiting on RFC Editor" or "RFC-Ed-Ack"
|
||||
# but RFC Editor state is IANA
|
||||
doc = Document.objects.create(name="draft-ietf-test3", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="rfcqueue"))
|
||||
doc.set_state(State.objects.get(type="draft-iana-action", slug="waitrfc"))
|
||||
doc.set_state(State.objects.get(type="draft-rfceditor", slug="iana"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
||||
|
||||
# draft with state other than "RFC Ed Queue" or "RFC Published"
|
||||
# that are in RFC Editor or IANA queues
|
||||
doc = Document.objects.create(name="draft-ietf-test4", type_id="draft")
|
||||
doc.set_state(State.objects.get(type="draft-iesg", slug="ann"))
|
||||
doc.set_state(State.objects.get(type="draft-rfceditor", slug="auth"))
|
||||
|
||||
r = self.client.get(urlreverse("ietf.sync.views.discrepancies"))
|
||||
self.assertTrue(doc.name in r.content)
|
8
ietf/sync/urls.py
Normal file
8
ietf/sync/urls.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^discrepancies/$', 'ietf.sync.views.discrepancies'),
|
||||
url(r'^iana/update/$', 'ietf.sync.views.update_iana'),
|
||||
url(r'^rfc-editor/update/$', 'ietf.sync.views.update_rfc_editor'),
|
||||
)
|
||||
|
79
ietf/sync/views.py
Normal file
79
ietf/sync/views.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
import subprocess, os
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.template.loader import render_to_string
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
|
||||
from ietf.ietfauth.decorators import role_required
|
||||
from ietf.doc.models import *
|
||||
from ietf.sync import iana, rfceditor
|
||||
from ietf.sync.discrepancies import find_discrepancies
|
||||
|
||||
SYNC_BIN_PATH = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../bin"))
|
||||
|
||||
#@role_required('Secretariat', 'IANA', 'RFC Editor')
|
||||
def discrepancies(request):
|
||||
sections = find_discrepancies()
|
||||
|
||||
return render_to_response("sync/discrepancies.html",
|
||||
dict(sections=sections),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
class UpdateIanaForm(forms.Form):
|
||||
protocols_page = forms.BooleanField(initial=False, required=False, help_text="For when a reference to an RFC has been added to <a href=\"%s\">the IANA protocols page</a>" % iana.PROTOCOLS_URL)
|
||||
changes = forms.BooleanField(initial=False, required=False, help_text="For new changes at <a href=\"%s\">the changes JSON dump</a>" % iana.CHANGES_URL)
|
||||
|
||||
def update_iana(request):
|
||||
if request.method == 'POST':
|
||||
form = UpdateIanaForm(request.POST)
|
||||
if form.is_valid():
|
||||
failed = False
|
||||
if form.cleaned_data["protocols_page"]:
|
||||
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "iana-protocols-updates")])
|
||||
if form.cleaned_data["changes"]:
|
||||
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "iana-changes-updates")])
|
||||
|
||||
if failed:
|
||||
return HttpResponse("FAIL")
|
||||
else:
|
||||
return HttpResponse("OK")
|
||||
else:
|
||||
form = UpdateIanaForm()
|
||||
|
||||
return render_to_response('sync/update.html',
|
||||
dict(form=form,
|
||||
org="IANA",
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
class UpdateRFCEditorForm(forms.Form):
|
||||
queue = forms.BooleanField(initial=False, required=False, help_text="For when <a href=\"%s\">queue2.xml</a> has been updated" % rfceditor.QUEUE_URL)
|
||||
index = forms.BooleanField(initial=False, required=False, help_text="For when <a href=\"%s\">rfc-index.xml</a> has been updated" % rfceditor.INDEX_URL)
|
||||
|
||||
def update_rfc_editor(request):
|
||||
if request.method == 'POST':
|
||||
form = UpdateRFCEditorForm(request.POST)
|
||||
if form.is_valid():
|
||||
failed = False
|
||||
if form.cleaned_data["queue"]:
|
||||
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "rfc-editor-queue-updates")])
|
||||
if form.cleaned_data["index"]:
|
||||
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "rfc-editor-index-updates")])
|
||||
|
||||
if failed:
|
||||
return HttpResponse("FAIL")
|
||||
else:
|
||||
return HttpResponse("OK")
|
||||
else:
|
||||
form = UpdateRFCEditorForm()
|
||||
|
||||
return render_to_response('sync/update.html',
|
||||
dict(form=form,
|
||||
org="RFC Editor",
|
||||
),
|
||||
context_instance=RequestContext(request))
|
37
ietf/templates/sync/discrepancies.html
Normal file
37
ietf/templates/sync/discrepancies.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Sync discrepancies{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
table.discrepancies td { padding-right: 0.2em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Sync discrepancies</h1>
|
||||
|
||||
{% for title, docs in sections %}
|
||||
<h3>{{ title }}</h3>
|
||||
|
||||
{% if docs %}
|
||||
<table class="discrepancies">
|
||||
<tr>
|
||||
<td>Draft Name</td>
|
||||
<td>IESG state</td>
|
||||
<td>RFC Editor state</td>
|
||||
<td>IANA Action state</td>
|
||||
</tr>
|
||||
{% for d in docs %}
|
||||
<tr id="d{{ d.pk }}">
|
||||
<td><a href="{{ d.get_absolute_url }}">{{ d.name }}</a></td>
|
||||
<td>{{ d.iesg_state|default:"-" }}</td>
|
||||
<td>{{ d.rfc_state|default:"-" }}</td>
|
||||
<td>{{ d.iana_action_state|default:"-" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
<p>None found.</p>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
{% endblock %}
|
18
ietf/templates/sync/discrepancies_report.txt
Normal file
18
ietf/templates/sync/discrepancies_report.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
{% autoescape off %}
|
||||
This is an automated report of current Datatracker sync discrepancies,
|
||||
also available at:
|
||||
|
||||
{{ url }}
|
||||
{% for title, docs in sections %}
|
||||
|
||||
{{ title|wordwrap:73 }}
|
||||
{% if docs %}{% for d in docs %}
|
||||
{{ d.name }}
|
||||
IESG: {{ d.iesg_state|default:"-" }}
|
||||
RFC Ed: {{ d.rfc_state|default:"-" }}
|
||||
IANA: {{ d.iana_action_state|default:"-" }}
|
||||
{{ base_url }}{{ d.get_absolute_url }}
|
||||
{% endfor %}{% else %}
|
||||
None found.
|
||||
{% endif %}{% endfor %}
|
||||
{% endautoescape %}
|
27
ietf/templates/sync/update.html
Normal file
27
ietf/templates/sync/update.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Trigger sync for {{ org }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.sync-form .help { font-style: italic; padding-left: 2em; }
|
||||
.sync-form input[type=submit] { margin-top: 1em; }
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1>Trigger sync for {{ org }}</h1>
|
||||
|
||||
<p>Update the Datatracker with information from {{ org }}. Select
|
||||
which parts to trigger a sync for:</p>
|
||||
|
||||
<form class="sync-form" action="" method="post">
|
||||
{% for field in form %}
|
||||
<div>
|
||||
{{ field }}
|
||||
{{ field.label_tag }}
|
||||
{% if field.help_text %}<span class="help">{{ field.help_text|safe }}</span>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<input type="submit" value="Trigger sync"/>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -66,6 +66,7 @@ urlpatterns = patterns('',
|
|||
(r'^submit/', include('ietf.submit.urls')),
|
||||
(r'^streams/', include('ietf.ietfworkflows.urls')),
|
||||
(r'^community/', include('ietf.community.urls')),
|
||||
(r'^sync/', include('ietf.sync.urls')),
|
||||
|
||||
(r'^$', 'ietf.idrfc.views.main'),
|
||||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
|
|
|
@ -114,6 +114,22 @@ def make_test_data():
|
|||
ascii="(System)",
|
||||
address="",
|
||||
)
|
||||
|
||||
# IANA and RFC Editor groups
|
||||
iana = Group.objects.create(
|
||||
name="IANA",
|
||||
acronym="iana",
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
parent=None,
|
||||
)
|
||||
rfc_editor = Group.objects.create(
|
||||
name="RFC Editor",
|
||||
acronym="rfc-edit",
|
||||
state_id="active",
|
||||
type_id="ietf",
|
||||
parent=None,
|
||||
)
|
||||
|
||||
if system_person.id != 0: # work around bug in Django
|
||||
Person.objects.filter(id=system_person.id).update(id=0)
|
||||
|
@ -248,6 +264,42 @@ def make_test_data():
|
|||
email=email,
|
||||
)
|
||||
|
||||
# IANA user
|
||||
u = User.objects.create(username="iana")
|
||||
p = Person.objects.create(
|
||||
name="Ina Iana",
|
||||
ascii="Ina Iana",
|
||||
user=u)
|
||||
Alias.objects.create(
|
||||
name=p.name,
|
||||
person=p)
|
||||
email = Email.objects.create(
|
||||
address="iana@ia.na",
|
||||
person=p)
|
||||
Role.objects.create(
|
||||
name_id="auth",
|
||||
group=iana,
|
||||
email=email,
|
||||
person=p,
|
||||
)
|
||||
|
||||
# RFC Editor user
|
||||
u = User.objects.create(username="rfc")
|
||||
p = Person.objects.create(
|
||||
name="Rfc Editor",
|
||||
ascii="Rfc Editor",
|
||||
user=u)
|
||||
email = Email.objects.create(
|
||||
address="rfc@edit.or",
|
||||
person=p)
|
||||
Role.objects.create(
|
||||
name_id="auth",
|
||||
group=rfc_editor,
|
||||
email=email,
|
||||
person=p,
|
||||
)
|
||||
|
||||
|
||||
# draft
|
||||
draft = Document.objects.create(
|
||||
name="draft-ietf-mars-test",
|
||||
|
|
Loading…
Reference in a new issue