diff --git a/ietf/sync/urls.py b/ietf/sync/urls.py index f99cc76c1..d04919822 100644 --- a/ietf/sync/urls.py +++ b/ietf/sync/urls.py @@ -2,7 +2,6 @@ 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'), + url(r'^(?P\w+)/notify/(?P\w+)/$', 'ietf.sync.views.notify'), ) diff --git a/ietf/sync/views.py b/ietf/sync/views.py index c6b9c7fc1..58d793c56 100644 --- a/ietf/sync/views.py +++ b/ietf/sync/views.py @@ -1,13 +1,15 @@ import subprocess, os -from django.http import HttpResponse +from django.http import HttpResponse, HttpResponseForbidden from django.shortcuts import render_to_response from django.template import RequestContext from django.template.loader import render_to_string +from django.conf import settings from django import forms from django.db.models import Q +from django.contrib.auth.models import User -from ietf.ietfauth.decorators import role_required +from ietf.ietfauth.decorators import role_required, has_role from ietf.doc.models import * from ietf.sync import iana, rfceditor from ietf.sync.discrepancies import find_discrepancies @@ -22,58 +24,79 @@ def discrepancies(request): dict(sections=sections), context_instance=RequestContext(request)) +def notify(request, org, notification): + """Notify that something has changed at another site to trigger a + run of one of the sync scripts.""" -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 the IANA protocols page" % iana.PROTOCOLS_URL) - changes = forms.BooleanField(initial=False, required=False, help_text="For new changes at the changes JSON dump" % iana.CHANGES_URL) + known_orgs = { + "iana": "IANA", + "rfceditor": "RFC Editor", + } -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 org not in known_orgs: + raise Http404 - if failed: - return HttpResponse("FAIL") - else: - return HttpResponse("OK") - else: - form = UpdateIanaForm() + # handle auth, to make it easier for the other end, you can send + # the username/password as POST parameters instead of having to + # visit the login page + user = request.user - 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 queue2.xml has been updated" % rfceditor.QUEUE_URL) - index = forms.BooleanField(initial=False, required=False, help_text="For when rfc-index.xml 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", + username = request.POST.get("username") or request.GET.get("username") + password = request.POST.get("password") or request.GET.get("password") + + if username and password: + if settings.SERVER_MODE == "production" and not request.is_secure(): + return HttpResponseForbidden("You must use HTTPS when sending username/password") + + if not user.is_authenticated(): + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + return HttpResponse("Invalid username/password") + + if not user.check_password(password): + return HttpResponse("Invalid username/password") + + if not has_role(user, ("Secretariat", known_orgs[org])): + return HttpResponseForbidden("You do not have the necessary permissions to view this page") + + known_notifications = { + "protocols": "an added reference to an RFC at the IANA protocols page" % iana.PROTOCOLS_URL, + "changes": "new changes at the changes JSON dump" % iana.CHANGES_URL, + "queue": "new changes to queue2.xml" % rfceditor.QUEUE_URL, + "index": "new changes to rfc-index.xml" % rfceditor.INDEX_URL, + } + + if notification not in known_notifications: + raise Http404 + + if request.method == "POST": + def runscript(name): + p = subprocess.Popen(["python", os.path.join(SYNC_BIN_PATH, name)], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = p.communicate() + return (p.returncode, out) + + if notification == "protocols": + failed, out = runscript("iana-protocols-updates") + + if notification == "changes": + failed, out = runscript("iana-changes-updates") + + if notification == "queue": + failed, out = runscript("rfc-editor-queue-updates") + + if notification == "index": + failed, out = runscript("rfc-editor-index-updates") + + if failed: + return HttpResponse("FAIL\n\n" + out, content_type="text/plain") + else: + return HttpResponse("OK", content_type="text/plain") + + return render_to_response('sync/notify.html', + dict(org=known_orgs[org], + notification=notification, + help_text=known_notifications[notification], ), context_instance=RequestContext(request)) diff --git a/ietf/templates/sync/notify.html b/ietf/templates/sync/notify.html new file mode 100644 index 000000000..4092bb535 --- /dev/null +++ b/ietf/templates/sync/notify.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %}Trigger {{ notification }} sync for {{ org }}{% endblock %} + +{% block content %} +

Trigger {{ notification }} sync for {{ org }}

+ +

Update the Datatracker with {{ help_text|safe }} at {{ org }}.

+ +
+ +
+{% endblock %} diff --git a/ietf/templates/sync/update.html b/ietf/templates/sync/update.html deleted file mode 100644 index 86b6a73f8..000000000 --- a/ietf/templates/sync/update.html +++ /dev/null @@ -1,27 +0,0 @@ -{% 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 %} -

Trigger sync for {{ org }}

- -

Update the Datatracker with information from {{ org }}. Select -which parts to trigger a sync for:

- -
-{% for field in form %} -
- {{ field }} - {{ field.label_tag }} - {% if field.help_text %}{{ field.help_text|safe }}{% endif %} -
-{% endfor %} - -
-{% endblock %}