from IANA as it turns out that the Datatracker is the authoritative source on these states. Also improve logging so that the raw JSON from IANA is dumped, the parsed JSON on imported changes is dumped and we write to syslog before starting a sync script in the notification view. - Legacy-Id: 5800
150 lines
5.8 KiB
Python
150 lines
5.8 KiB
Python
import subprocess, os, json
|
|
|
|
from django.http import HttpResponse, HttpResponseForbidden, HttpResponseServerError, HttpResponseRedirect, Http404
|
|
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, has_role
|
|
from ietf.doc.models import *
|
|
from ietf.sync import iana, rfceditor
|
|
from ietf.sync.discrepancies import find_discrepancies
|
|
from ietf.utils.serialize import object_as_shallow_dict
|
|
|
|
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))
|
|
|
|
def notify(request, org, notification):
|
|
"""Notify that something has changed at another site to trigger a
|
|
run of one of the sync scripts."""
|
|
|
|
known_orgs = {
|
|
"iana": "IANA",
|
|
"rfceditor": "RFC Editor",
|
|
}
|
|
|
|
if org not in known_orgs:
|
|
raise Http404
|
|
|
|
# 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
|
|
|
|
username = request.POST.get("username") or request.GET.get("username")
|
|
password = request.POST.get("password") or request.GET.get("password")
|
|
|
|
if username != None and password != None:
|
|
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 <a href=\"%s\">the IANA protocols page</a>" % settings.IANA_SYNC_PROTOCOLS_URL,
|
|
"changes": "new changes at <a href=\"%s\">the changes JSON dump</a>" % settings.IANA_SYNC_CHANGES_URL,
|
|
"queue": "new changes to <a href=\"%s\">queue2.xml</a>" % settings.RFC_EDITOR_QUEUE_URL,
|
|
"index": "new changes to <a href=\"%s\">rfc-index.xml</a>" % settings.RFC_EDITOR_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)
|
|
|
|
import syslog
|
|
syslog.syslog("Running sync script from notify view POST")
|
|
|
|
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 HttpResponseServerError("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))
|
|
|
|
@role_required('Secretariat', 'RFC Editor')
|
|
def rfceditor_undo(request):
|
|
"""Undo a DocEvent."""
|
|
events = StateDocEvent.objects.filter(state_type="draft-rfceditor",
|
|
time__gte=datetime.datetime.now() - datetime.timedelta(weeks=1)
|
|
).order_by("-time", "-id")
|
|
|
|
if request.method == "POST":
|
|
try:
|
|
eid = int(request.POST.get("event", ""))
|
|
except ValueError:
|
|
return HttpResponse("Could not parse event id")
|
|
|
|
try:
|
|
e = events.get(id=eid)
|
|
except StateDocEvent.DoesNotExist:
|
|
return HttpResponse("Event does not exist")
|
|
|
|
doc = e.doc
|
|
|
|
# possibly reset the state of the document
|
|
all_events = StateDocEvent.objects.filter(doc=doc, state_type="draft-rfceditor").order_by("-time", "-id")
|
|
if all_events and all_events[0] == e:
|
|
if len(all_events) > 1:
|
|
doc.set_state(all_events[1].state)
|
|
else:
|
|
doc.unset_state("draft-rfceditor")
|
|
|
|
dump = DeletedEvent()
|
|
dump.content_type = ContentType.objects.get_for_model(type(e))
|
|
dump.json = json.dumps(object_as_shallow_dict(e), indent=2)
|
|
dump.by = request.user.person
|
|
dump.save()
|
|
|
|
e.delete()
|
|
|
|
return HttpResponseRedirect(urlreverse("ietf.sync.views.rfceditor_undo"))
|
|
|
|
return render_to_response('sync/rfceditor_undo.html',
|
|
dict(events=events,
|
|
),
|
|
context_instance=RequestContext(request))
|