datatracker/ietf/idrfc/views_doc.py
2012-01-24 17:17:24 +00:00

304 lines
13 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
from datetime import datetime, time
from django.http import HttpResponse, Http404
from django.shortcuts import render_to_response, get_object_or_404
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.models import RfcIndex, DraftVersions
from ietf.idrfc.idrfc_wrapper import BallotWrapper, IdWrapper, RfcWrapper
from ietf.ietfworkflows.utils import get_full_info_for_draft
def document_debug(request, name):
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)
return HttpResponse(doc.to_json(), mimetype='text/plain')
def _get_html(key, filename):
f = None
try:
f = open(filename, 'rb')
raw_content = f.read()
except IOError:
return ("Error; cannot read ("+key+")", "")
finally:
if f:
f.close()
(c1,c2) = markup_txt.markup(raw_content)
return (c1,c2)
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)
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(request, name, tab):
if tab is None:
tab = "document"
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
(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://tools.ietf.org/rfcdiff?url2=%s">diff from -%02d</a>)' % (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 = 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):
if x['date']:
x['date'] = datetime.combine(x['date'], time(0,0,0))
else:
x['date'] = 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):
r = re.compile("^rfc([1-9][0-9]*)$")
m = r.match(name)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.doc.models import DocAlias
alias = get_object_or_404(DocAlias, name=name)
d = get_object_or_404(InternetDraft, name=alias.document.name)
try:
if not d.ballot.ballot_issued:
raise Http404
except BallotInfo.DoesNotExist:
raise Http404
return (BallotWrapper(d), RfcWrapper(d) if m else IdWrapper(d))
if m:
rfc_number = int(m.group(1))
rfci = get_object_or_404(RfcIndex, rfc_number=rfc_number)
id = get_object_or_404(IDInternal, rfc_flag=1, draft=rfc_number)
doc = RfcWrapper(rfci, idinternal=id)
else:
id = get_object_or_404(IDInternal, rfc_flag=0, draft__filename=name)
doc = IdWrapper(id)
try:
if not id.ballot.ballot_issued:
raise Http404
except BallotInfo.DoesNotExist:
raise Http404
ballot = BallotWrapper(id)
return ballot, doc
def document_ballot(request, name):
ballot, doc = get_ballot(name)
return render_to_response('idrfc/doc_ballot.html', {'ballot':ballot, 'doc':doc}, context_instance=RequestContext(request))
def ballot_tsv(request, name):
ballot, doc = 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 = get_ballot(name)
response = HttpResponse(mimetype='text/plain')
response.write(json.dumps(ballot.dict(), indent=2))
return response