datatracker/ietf/idrfc/views_doc.py
Ole Laursen 6062e16c2d Email IANA and RFC Editor when a draft is pulled from the queue at the
Datatracker, add page for editing IANA states, add more info to the
/doc/draft-XXXXX/doc.json dump for the RFC Editor, add page for
editing consensus, add page for requesting publication at the RFC
Editor for alternate streams (this will email the RFC Editor and set
the draft in the appropriate state), make it possible for alternate
streams to change the intended RFC status of a draft in the stream,
refactor how IANA copies are handled slightly so it's less code, put
drafts automatically in IANA Review "Need Review" state upon last
call, fix a bug in ballot issuing, remove a bit of dead code
 - Legacy-Id: 4857
2012-09-17 16:15:45 +00:00

659 lines
28 KiB
Python

# Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
#
# * Neither the name of the Nokia Corporation and/or its
# subsidiary(-ies) nor the names of its contributors may be used
# to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import re, os, datetime
from django.http import HttpResponse, Http404
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.template.loader import render_to_string
from django.template.defaultfilters import truncatewords_html
from django.utils import simplejson as json
from django.utils.decorators import decorator_from_middleware
from django.middleware.gzip import GZipMiddleware
from django.core.urlresolvers import reverse as urlreverse, NoReverseMatch
from django.conf import settings
from ietf.idtracker.models import InternetDraft, IDInternal, BallotInfo, DocumentComment
from ietf.idtracker.templatetags.ietf_filters import format_textarea, fill
from ietf.idrfc import markup_txt
from ietf.idrfc.utils import *
from ietf.idrfc.models import RfcIndex, DraftVersions
from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper
from ietf.ietfworkflows.utils import get_full_info_for_draft
from ietf.doc.models import *
from ietf.doc.utils import *
from ietf.utils.history import find_history_active_at
from ietf.ietfauth.decorators import has_role
def render_document_top(request, doc, tab, name):
tabs = []
tabs.append(("Document", "document", urlreverse("ietf.idrfc.views_doc.document_main", kwargs=dict(name=name)), True))
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
if doc.type_id in ("draft","conflrev"):
# if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot:
tabs.append(("IESG Evaluation Record", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=name)), ballot))
elif doc.type_id == "charter":
tabs.append(("IESG Review", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=name)), ballot))
# FIXME: if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot:
if doc.type_id != "conflrev":
tabs.append(("IESG Writeups", "writeup", urlreverse("ietf.idrfc.views_doc.document_writeup", kwargs=dict(name=doc.name)), True))
tabs.append(("History", "history", urlreverse("ietf.idrfc.views_doc.document_history", kwargs=dict(name=doc.name)), True))
name = doc.canonical_name()
if name.startswith("rfc"):
name = "RFC %s" % name[3:]
else:
name += "-" + doc.rev
return render_to_string("idrfc/document_top.html",
dict(doc=doc,
tabs=tabs,
selected=tab,
name=name))
def document_main(request, name, rev=None):
if name.lower().startswith("draft") or name.lower().startswith("rfc"):
if rev != None: # no support for old revisions at the moment
raise Http404()
return document_main_idrfc(request, name, tab="document")
doc = get_object_or_404(Document, docalias__name=name)
group = doc.group
if doc.type_id == 'conflrev':
conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target.document
revisions = []
for h in doc.history_set.order_by("time", "id"):
if h.rev and not h.rev in revisions:
revisions.append(h.rev)
if not doc.rev in revisions:
revisions.append(doc.rev)
snapshot = False
if rev != None:
if rev == doc.rev:
return redirect('doc_view', name=name)
# find the entry in the history
for h in doc.history_set.order_by("-time"):
if rev == h.rev:
snapshot = True
doc = h
break
if not snapshot:
return redirect('doc_view', name=name)
if doc.type_id == "charter":
# find old group, too
gh = find_history_active_at(doc.group, doc.time)
if gh:
group = gh
top = render_document_top(request, doc, "document", name)
telechat = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
if telechat and not telechat.telechat_date:
telechat = None
if telechat and telechat.telechat_date < datetime.date.today():
telechat = None
if doc.type_id == "charter":
filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev)
content = _get_html(filename, os.path.join(settings.CHARTER_PATH, filename), split=False)
ballot_summary = None
if doc.get_state_slug() in ("intrev", "iesgrev"):
ballot_summary = needed_ballot_positions(doc, active_ballot_positions(doc).values())
return render_to_response("idrfc/document_charter.html",
dict(doc=doc,
top=top,
chartering=get_chartering_type(doc),
content=content,
txt_url=settings.CHARTER_TXT_URL + filename,
revisions=revisions,
snapshot=snapshot,
telechat=telechat,
ballot_summary=ballot_summary,
group=group,
),
context_instance=RequestContext(request))
if doc.type_id == "conflrev":
filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev)
pathname = os.path.join(settings.CONFLICT_REVIEW_PATH,filename)
if doc.rev == "00" and not os.path.isfile(pathname):
# This could move to a template
content = "A conflict review response has not yet been proposed."
else:
content = _get_html(filename, pathname, split=False)
ballot_summary = None
if doc.get_state_slug() in ("iesgeval"):
ballot_summary = needed_ballot_positions(doc, active_ballot_positions(doc).values())
return render_to_response("idrfc/document_conflict_review.html",
dict(doc=doc,
top=top,
content=content,
revisions=revisions,
snapshot=snapshot,
telechat=telechat,
conflictdoc=conflictdoc,
ballot_summary=ballot_summary,
approved_states=('appr-reqnopub-pend','appr-reqnopub-sent','appr-noprob-pend','appr-noprob-sent')
),
context_instance=RequestContext(request))
raise Http404()
def document_history(request, name):
# todo: remove need for specific handling of drafts by porting the
# two event text hacks
if name.lower().startswith("draft") or name.lower().startswith("rfc"):
return document_main_idrfc(request, name, "history")
doc = get_object_or_404(Document, docalias__name=name)
top = render_document_top(request, doc, "history", name)
diff_documents = [ doc ]
diff_documents.extend(Document.objects.filter(docalias__relateddocument__source=doc, docalias__relateddocument__relationship="replaces"))
# pick up revisions from events
diff_revisions = []
seen = set()
diffable = name.startswith("draft") or name.startswith("charter")
if diffable:
for e in NewRevisionDocEvent.objects.filter(type="new_revision", doc__in=diff_documents).select_related('doc').order_by("-time", "-id"):
if not (e.doc.name, e.rev) in seen:
seen.add((e.doc.name, e.rev))
url = ""
if name.startswith("charter"):
h = find_history_active_at(e.doc, e.time)
url = settings.CHARTER_TXT_URL + ("%s-%s.txt" % ((h or doc).canonical_name(), e.rev))
elif name.startswith("draft"):
# rfcdiff tool has special support for IDs
url = e.doc.name + "-" + e.rev
diff_revisions.append((e.doc.name, e.rev, e.time, url))
# grab event history
events = doc.docevent_set.all().order_by("-time", "-id").select_related("by")
augment_events_with_revision(doc, events)
return render_to_response("idrfc/document_history.html",
dict(doc=doc,
top=top,
diff_revisions=diff_revisions,
events=events,
),
context_instance=RequestContext(request))
def document_writeup(request, name):
if name.lower().startswith("draft") or name.lower().startswith("rfc"):
# todo: migrate idrfc to pattern below
return document_main_idrfc(request, name, "writeup")
doc = get_object_or_404(Document, docalias__name=name)
top = render_document_top(request, doc, "writeup", name)
writeups = []
if doc.type_id == "charter":
e = doc.latest_event(WriteupDocEvent, type="changed_review_announcement")
writeups.append(("WG Review Announcement",
e.text if e else "",
urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="review"))))
e = doc.latest_event(WriteupDocEvent, type="changed_action_announcement")
writeups.append(("WG Action Announcement",
e.text if e else "",
urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="action"))))
if doc.latest_event(BallotDocEvent, type="created_ballot"):
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
writeups.append(("Ballot Announcement",
e.text if e else "",
urlreverse("ietf.wgcharter.views.ballot_writeupnotes", kwargs=dict(name=doc.name))))
if not writeups:
raise Http404()
return render_to_response("idrfc/document_writeup.html",
dict(doc=doc,
top=top,
writeups=writeups,
can_edit=has_role(request.user, ("Area Director", "Secretariat")),
),
context_instance=RequestContext(request))
def document_ballot_content(request, doc, ballot_id, editable=True):
"""Render HTML string with content of ballot page."""
all_ballots = list(BallotDocEvent.objects.filter(doc=doc, type="created_ballot").order_by("time"))
augment_events_with_revision(doc, all_ballots)
ballot = None
if ballot_id != None:
ballot_id = int(ballot_id)
for b in all_ballots:
if b.id == ballot_id:
ballot = b
break
elif all_ballots:
ballot = all_ballots[-1]
if not ballot:
raise Http404
deferred = doc.active_defer_event()
# collect positions
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active").distinct())
positions = []
seen = {}
for e in BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ballot=ballot).select_related('ad', 'pos').order_by("-time", '-id'):
if e.ad not in seen:
e.old_ad = e.ad not in active_ads
e.old_positions = []
positions.append(e)
seen[e.ad] = e
else:
latest = seen[e.ad]
if latest.old_positions:
prev = latest.old_positions[-1]
else:
prev = latest.pos.name
if e.pos.name != prev:
latest.old_positions.append(e.pos.name)
# add any missing ADs through fake No Record events
norecord = BallotPositionName.objects.get(slug="norecord")
for ad in active_ads:
if ad not in seen:
e = BallotPositionDocEvent(type="changed_ballot_position", doc=doc, ad=ad)
e.pos = norecord
e.old_ad = False
e.old_positions = []
positions.append(e)
# put into position groups
position_groups = []
for n in BallotPositionName.objects.filter(slug__in=[p.pos_id for p in positions]).order_by('order'):
g = (n, [p for p in positions if p.pos_id == n.slug])
g[1].sort(key=lambda p: (p.old_ad, p.ad.plain_name()))
if n.blocking:
position_groups.insert(0, g)
else:
position_groups.append(g)
summary = needed_ballot_positions(doc, [p for p in positions if not p.old_ad])
text_positions = [p for p in positions if p.discuss or p.comment]
text_positions.sort(key=lambda p: (p.old_ad, p.ad.plain_name()))
ballot_open = not BallotDocEvent.objects.filter(doc=doc,
type__in=("closed_ballot", "created_ballot"),
time__gt=ballot.time,
ballot_type=ballot.ballot_type)
if not ballot_open:
editable = False
return render_to_string("idrfc/document_ballot_content.html",
dict(doc=doc,
ballot=ballot,
position_groups=position_groups,
text_positions=text_positions,
editable=editable,
ballot_open=ballot_open,
deferred=deferred,
summary=summary,
all_ballots=all_ballots,
),
context_instance=RequestContext(request))
def document_ballot(request, name, ballot_id=None):
doc = get_object_or_404(Document, docalias__name=name)
top = render_document_top(request, doc, "ballot", name)
c = document_ballot_content(request, doc, ballot_id, editable=True)
return render_to_response("idrfc/document_ballot.html",
dict(doc=doc,
top=top,
ballot_content=c,
),
context_instance=RequestContext(request))
def document_json(request, name):
# old interface
r = re.compile("^rfc([1-9][0-9]*)$")
m = r.match(name)
if m:
rfc_number = int(m.group(1))
rfci = get_object_or_404(RfcIndex, rfc_number=rfc_number)
doc = RfcWrapper(rfci)
else:
id = get_object_or_404(InternetDraft, filename=name)
doc = IdWrapper(draft=id)
from idrfc_wrapper import jsonify_helper
if isinstance(doc, RfcWrapper):
data = jsonify_helper(doc, ['rfc_number', 'title', 'publication_date', 'maturity_level', 'obsoleted_by','obsoletes','updated_by','updates','also','has_errata','stream_name','file_types','in_ietf_process', 'friendly_state'])
else:
data = jsonify_helper(doc, ['draft_name', 'draft_status', 'latest_revision', 'rfc_number', 'title', 'tracker_id', 'publication_date','rfc_editor_state', 'replaced_by', 'replaces', 'in_ietf_process', 'file_types', 'group_acronym', 'stream_id','friendly_state', 'abstract', 'ad_name'])
if doc.in_ietf_process():
data['ietf_process'] = doc.ietf_process.dict()
# add some more fields using the new interface
d = get_object_or_404(Document, docalias__name=name)
data["authors"] = [
dict(name=e.person.name,
email=e.address,
affiliation=e.person.affiliation)
for e in Email.objects.filter(documentauthor__document=d).select_related("person").order_by("documentauthor__order")
]
e = d.latest_event(ConsensusDocEvent, type="changed_consensus")
data["consensus"] = e.consensus if e else None
data["stream"] = d.stream.name if d.stream else None
data["shepherd"] = d.shepherd.formatted_email() if d.shepherd else None
def state_name(s):
return s.name if s else None
data["iana_review_state"] = state_name(d.get_state("draft-iana-review"))
data["iana_action_state"] = state_name(d.get_state("draft-iana-action"))
return HttpResponse(json.dumps(data, indent=2), mimetype='text/plain')
def _get_html(key, filename, split=True):
return get_document_content(key, filename, split=split, markup=True)
def include_text(request):
include_text = request.GET.get( 'include_text' )
if "full_draft" in request.COOKIES:
if request.COOKIES["full_draft"] == "on":
include_text = 1
return include_text
def document_main_rfc(request, rfc_number, tab):
rfci = get_object_or_404(RfcIndex, rfc_number=rfc_number, states__type="draft", states__slug="rfc")
rfci.viewing_as_rfc = True
doc = RfcWrapper(rfci)
info = {}
info['is_rfc'] = True
info['has_pdf'] = (".pdf" in doc.file_types())
info['has_txt'] = (".txt" in doc.file_types())
info['has_ps'] = (".ps" in doc.file_types())
if info['has_txt']:
(content1, content2) = _get_html(
"rfc"+str(rfc_number)+",html",
os.path.join(settings.RFC_PATH, "rfc"+str(rfc_number)+".txt"))
else:
content1 = ""
content2 = ""
history = _get_history(doc, None)
template = "idrfc/doc_tab_%s" % tab
if tab == "document":
template += "_rfc"
return render_to_response(template + ".html",
{'content1':content1, 'content2':content2,
'doc':doc, 'info':info, 'tab':tab,
'include_text':include_text(request),
'history':history},
context_instance=RequestContext(request));
@decorator_from_middleware(GZipMiddleware)
def document_main_idrfc(request, name, tab):
r = re.compile("^rfc([1-9][0-9]*)$")
m = r.match(name)
if m:
return document_main_rfc(request, int(m.group(1)), tab)
id = get_object_or_404(InternetDraft, filename=name)
doc = IdWrapper(id)
info = {}
info['has_pdf'] = (".pdf" in doc.file_types())
info['is_rfc'] = False
info['conflict_reviews'] = [ rel.source for alias in id.docalias_set.all() for rel in alias.relateddocument_set.filter(relationship='conflrev') ]
info['rfc_editor_state'] = id.get_state("draft-rfceditor")
info['iana_review_state'] = id.get_state("draft-iana-review")
info['iana_action_state'] = id.get_state("draft-iana-action")
e = id.latest_event(ConsensusDocEvent, type="changed_consensus")
info["consensus"] = nice_consensus(e and e.consensus)
info["can_edit_consensus"] = can_edit_consensus(id, request.user)
info["can_edit_intended_std_level"] = can_edit_intended_std_level(id, request.user)
(content1, content2) = _get_html(
str(name)+","+str(id.revision)+",html",
os.path.join(settings.INTERNET_DRAFT_PATH, name+"-"+id.revision+".txt"))
versions = _get_versions(id)
history = _get_history(doc, versions)
template = "idrfc/doc_tab_%s" % tab
if tab == "document":
template += "_id"
return render_to_response(template + ".html",
{'content1':content1, 'content2':content2,
'doc':doc, 'info':info, 'tab':tab,
'include_text':include_text(request),
'stream_info': get_full_info_for_draft(id),
'versions':versions, 'history':history},
context_instance=RequestContext(request));
# doc is either IdWrapper or RfcWrapper
def _get_history(doc, versions):
results = []
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
versions = [] # clear versions
event_holder = doc._draft if hasattr(doc, "_draft") else doc._rfcindex
for e in event_holder.docevent_set.all().select_related('by').order_by('-time', 'id'):
info = {}
if e.type == "new_revision":
filename = u"%s-%s" % (e.doc.name, e.newrevisiondocevent.rev)
e.desc = 'New version available: <a href="http://tools.ietf.org/id/%s.txt">%s</a>' % (filename, filename)
if int(e.newrevisiondocevent.rev) != 0:
e.desc += ' (<a href="http:%s?url2=%s">diff from -%02d</a>)' % (settings.RFCDIFF_PREFIX, filename, int(e.newrevisiondocevent.rev) - 1)
info["dontmolest"] = True
multiset_ballot_text = "This was part of a ballot set with: "
if e.desc.startswith(multiset_ballot_text):
names = [ n.strip() for n in e.desc[len(multiset_ballot_text):].split(",") ]
e.desc = multiset_ballot_text + ", ".join(u'<a href="%s">%s</a>' % (urlreverse("doc_view", kwargs={'name': n }), n) for n in names)
info["dontmolest"] = True
info['text'] = e.desc
info['by'] = e.by.plain_name()
info['textSnippet'] = truncatewords_html(format_textarea(fill(info['text'], 80)), 25)
info['snipped'] = info['textSnippet'][-3:] == "..." and e.type != "new_revision"
results.append({'comment':e, 'info':info, 'date':e.time, 'is_com':True})
prev_rev = "00"
# actually, we're already sorted and this ruins the sort from
# the ids which is sometimes needed, so the function should be
# rewritten to not rely on a resort
results.sort(key=lambda x: x['date'])
for o in results:
e = o["comment"]
if e.type == "new_revision":
e.version = e.newrevisiondocevent.rev
else:
e.version = prev_rev
prev_rev = e.version
else:
if doc.is_id_wrapper:
comments = DocumentComment.objects.filter(document=doc.tracker_id).exclude(rfc_flag=1)
else:
comments = DocumentComment.objects.filter(document=doc.rfc_number,rfc_flag=1)
if len(comments) > 0:
# also include rfc_flag=NULL, but only if at least one
# comment with rfc_flag=1 exists (usually NULL means same as 0)
comments = DocumentComment.objects.filter(document=doc.rfc_number).exclude(rfc_flag=0)
for comment in comments.order_by('-date','-time','-id').filter(public_flag=1).select_related('created_by'):
info = {}
info['text'] = comment.comment_text
info['by'] = comment.get_fullname()
info['textSnippet'] = truncatewords_html(format_textarea(fill(info['text'], 80)), 25)
info['snipped'] = info['textSnippet'][-3:] == "..."
results.append({'comment':comment, 'info':info, 'date':comment.datetime(), 'is_com':True})
if doc.is_id_wrapper and versions:
for v in versions:
if v['draft_name'] == doc.draft_name:
v = dict(v) # copy it, since we're modifying datetimes later
v['is_rev'] = True
results.insert(0, v)
if not settings.USE_DB_REDESIGN_PROXY_CLASSES and doc.is_id_wrapper and doc.draft_status == "Expired" and doc._draft.expiration_date:
results.append({'is_text':True, 'date':doc._draft.expiration_date, 'text':'Draft expired'})
if not settings.USE_DB_REDESIGN_PROXY_CLASSES and doc.is_rfc_wrapper:
text = 'RFC Published'
if doc.draft_name:
try:
text = 'RFC Published (see <a href="%s">%s</a> for earlier history)' % (urlreverse('doc_view', args=[doc.draft_name]),doc.draft_name)
except NoReverseMatch:
pass
results.append({'is_text':True, 'date':doc.publication_date, 'text':text})
# convert plain dates to datetimes (required for sorting)
for x in results:
if not isinstance(x['date'], datetime.datetime):
if x['date']:
x['date'] = datetime.datetime.combine(x['date'], datetime.time(0,0,0))
else:
x['date'] = datetime.datetime(1970,1,1)
results.sort(key=lambda x: x['date'])
results.reverse()
return results
# takes InternetDraft instance
def _get_versions(draft, include_replaced=True):
ov = []
ov.append({"draft_name":draft.filename, "revision":draft.revision_display(), "date":draft.revision_date})
if include_replaced:
draft_list = [draft]+list(draft.replaces_set.all())
else:
draft_list = [draft]
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.doc.models import NewRevisionDocEvent
for e in NewRevisionDocEvent.objects.filter(type="new_revision", doc__in=draft_list).select_related('doc').order_by("-time", "-id"):
if not (e.doc.name == draft.name and e.rev == draft.rev):
ov.append(dict(draft_name=e.doc.name, revision=e.rev, date=e.time.date()))
return ov
for d in draft_list:
for v in DraftVersions.objects.filter(filename=d.filename).order_by('-revision'):
if (d.filename == draft.filename) and (draft.revision_display() == v.revision):
continue
ov.append({"draft_name":d.filename, "revision":v.revision, "date":v.revision_date})
return ov
def get_ballot(name):
from ietf.doc.models import DocAlias
alias = get_object_or_404(DocAlias, name=name)
d = alias.document
id = None
bw = None
dw = None
if (d.type_id=='draft'):
id = get_object_or_404(InternetDraft, name=d.name)
try:
if not id.ballot.ballot_issued:
raise Http404
except BallotInfo.DoesNotExist:
raise Http404
bw = BallotWrapper(id) # XXX Fixme: Eliminate this as we go forward
# Python caches ~100 regex'es -- explicitly compiling it inside a method
# (where you then throw away the compiled version!) doesn't make sense at
# all.
if re.search("^rfc([1-9][0-9]*)$", name):
id.viewing_as_rfc = True
dw = RfcWrapper(id)
else:
dw = IdWrapper(id)
# XXX Fixme: Eliminate 'dw' as we go forward
try:
b = d.latest_event(BallotDocEvent, type="created_ballot")
except BallotDocEvent.DoesNotExist:
raise Http404
return (bw, dw, b, d)
def ballot_for_popup(request, name):
doc = get_object_or_404(Document, docalias__name=name)
return HttpResponse(document_ballot_content(request, doc, ballot_id=None, editable=False))
def ballot_html(request, name):
bw, dw, ballot, doc = get_ballot(name)
content = document_ballot_content(request, doc, ballot.pk, editable=True)
return HttpResponse(content)
def ballot_tsv(request, name):
ballot, doc, b, d = get_ballot(name)
return HttpResponse(render_to_string('idrfc/ballot.tsv', {'ballot':ballot}, RequestContext(request)), content_type="text/plain")
def ballot_json(request, name):
ballot, doc, b, d = get_ballot(name)
response = HttpResponse(mimetype='text/plain')
response.write(json.dumps(ballot.dict(), indent=2))
return response