Skip to content

Commit ff077f4

Browse files
committed
Rename /sync/iana|rfceditor/update/ to /sync/iana|rfceditor/notify/,
and put the thing to notify in the URL, like /sync/iana/notify/changes/, instead of using POST parameters; refactor the two sync views to use the same for IANA and RFC Editor; require Secretariat or IANA/RFC Editor roles for triggering the updates and support passing username and password for auth to make it easier in the other end once we move away from HTTP Auth - Legacy-Id: 4868
1 parent 444a57a commit ff077f4

4 files changed

Lines changed: 89 additions & 81 deletions

File tree

ietf/sync/urls.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
urlpatterns = patterns('',
44
url(r'^discrepancies/$', 'ietf.sync.views.discrepancies'),
5-
url(r'^iana/update/$', 'ietf.sync.views.update_iana'),
6-
url(r'^rfc-editor/update/$', 'ietf.sync.views.update_rfc_editor'),
5+
url(r'^(?P<org>\w+)/notify/(?P<notification>\w+)/$', 'ietf.sync.views.notify'),
76
)
87

ietf/sync/views.py

Lines changed: 75 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import subprocess, os
22

3-
from django.http import HttpResponse
3+
from django.http import HttpResponse, HttpResponseForbidden
44
from django.shortcuts import render_to_response
55
from django.template import RequestContext
66
from django.template.loader import render_to_string
7+
from django.conf import settings
78
from django import forms
89
from django.db.models import Q
10+
from django.contrib.auth.models import User
911

10-
from ietf.ietfauth.decorators import role_required
12+
from ietf.ietfauth.decorators import role_required, has_role
1113
from ietf.doc.models import *
1214
from ietf.sync import iana, rfceditor
1315
from ietf.sync.discrepancies import find_discrepancies
@@ -22,58 +24,79 @@ def discrepancies(request):
2224
dict(sections=sections),
2325
context_instance=RequestContext(request))
2426

27+
def notify(request, org, notification):
28+
"""Notify that something has changed at another site to trigger a
29+
run of one of the sync scripts."""
2530

26-
class UpdateIanaForm(forms.Form):
27-
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)
28-
changes = forms.BooleanField(initial=False, required=False, help_text="For new changes at <a href=\"%s\">the changes JSON dump</a>" % iana.CHANGES_URL)
29-
30-
def update_iana(request):
31-
if request.method == 'POST':
32-
form = UpdateIanaForm(request.POST)
33-
if form.is_valid():
34-
failed = False
35-
if form.cleaned_data["protocols_page"]:
36-
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "iana-protocols-updates")])
37-
if form.cleaned_data["changes"]:
38-
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "iana-changes-updates")])
39-
40-
if failed:
41-
return HttpResponse("FAIL")
42-
else:
43-
return HttpResponse("OK")
44-
else:
45-
form = UpdateIanaForm()
46-
47-
return render_to_response('sync/update.html',
48-
dict(form=form,
49-
org="IANA",
50-
),
51-
context_instance=RequestContext(request))
31+
known_orgs = {
32+
"iana": "IANA",
33+
"rfceditor": "RFC Editor",
34+
}
35+
36+
if org not in known_orgs:
37+
raise Http404
38+
39+
# handle auth, to make it easier for the other end, you can send
40+
# the username/password as POST parameters instead of having to
41+
# visit the login page
42+
user = request.user
43+
44+
username = request.POST.get("username") or request.GET.get("username")
45+
password = request.POST.get("password") or request.GET.get("password")
46+
47+
if username and password:
48+
if settings.SERVER_MODE == "production" and not request.is_secure():
49+
return HttpResponseForbidden("You must use HTTPS when sending username/password")
50+
51+
if not user.is_authenticated():
52+
try:
53+
user = User.objects.get(username=username)
54+
except User.DoesNotExist:
55+
return HttpResponse("Invalid username/password")
56+
57+
if not user.check_password(password):
58+
return HttpResponse("Invalid username/password")
59+
60+
if not has_role(user, ("Secretariat", known_orgs[org])):
61+
return HttpResponseForbidden("You do not have the necessary permissions to view this page")
62+
63+
known_notifications = {
64+
"protocols": "an added reference to an RFC at <a href=\"%s\">the IANA protocols page</a>" % iana.PROTOCOLS_URL,
65+
"changes": "new changes at <a href=\"%s\">the changes JSON dump</a>" % iana.CHANGES_URL,
66+
"queue": "new changes to <a href=\"%s\">queue2.xml</a>" % rfceditor.QUEUE_URL,
67+
"index": "new changes to <a href=\"%s\">rfc-index.xml</a>" % rfceditor.INDEX_URL,
68+
}
69+
70+
if notification not in known_notifications:
71+
raise Http404
72+
73+
if request.method == "POST":
74+
def runscript(name):
75+
p = subprocess.Popen(["python", os.path.join(SYNC_BIN_PATH, name)],
76+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
77+
out, _ = p.communicate()
78+
return (p.returncode, out)
79+
80+
if notification == "protocols":
81+
failed, out = runscript("iana-protocols-updates")
82+
83+
if notification == "changes":
84+
failed, out = runscript("iana-changes-updates")
85+
86+
if notification == "queue":
87+
failed, out = runscript("rfc-editor-queue-updates")
88+
89+
if notification == "index":
90+
failed, out = runscript("rfc-editor-index-updates")
5291

92+
if failed:
93+
return HttpResponse("FAIL\n\n" + out, content_type="text/plain")
94+
else:
95+
return HttpResponse("OK", content_type="text/plain")
5396

54-
class UpdateRFCEditorForm(forms.Form):
55-
queue = forms.BooleanField(initial=False, required=False, help_text="For when <a href=\"%s\">queue2.xml</a> has been updated" % rfceditor.QUEUE_URL)
56-
index = forms.BooleanField(initial=False, required=False, help_text="For when <a href=\"%s\">rfc-index.xml</a> has been updated" % rfceditor.INDEX_URL)
57-
58-
def update_rfc_editor(request):
59-
if request.method == 'POST':
60-
form = UpdateRFCEditorForm(request.POST)
61-
if form.is_valid():
62-
failed = False
63-
if form.cleaned_data["queue"]:
64-
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "rfc-editor-queue-updates")])
65-
if form.cleaned_data["index"]:
66-
failed = failed or subprocess.call(["python", os.path.join(SYNC_BIN_PATH, "rfc-editor-index-updates")])
67-
68-
if failed:
69-
return HttpResponse("FAIL")
70-
else:
71-
return HttpResponse("OK")
72-
else:
73-
form = UpdateRFCEditorForm()
74-
75-
return render_to_response('sync/update.html',
76-
dict(form=form,
77-
org="RFC Editor",
97+
return render_to_response('sync/notify.html',
98+
dict(org=known_orgs[org],
99+
notification=notification,
100+
help_text=known_notifications[notification],
78101
),
79102
context_instance=RequestContext(request))

ietf/templates/sync/notify.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{% extends "base.html" %}
2+
3+
{% block title %}Trigger {{ notification }} sync for {{ org }}{% endblock %}
4+
5+
{% block content %}
6+
<h1>Trigger {{ notification }} sync for {{ org }}</h1>
7+
8+
<p>Update the Datatracker with {{ help_text|safe }} at {{ org }}.</p>
9+
10+
<form class="sync-form" notification="" method="post">
11+
<input type="submit" value="Trigger {{ notification }} sync"/>
12+
</form>
13+
{% endblock %}

ietf/templates/sync/update.html

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)