Merged in more shim-layer removals from olau@iola.dk
(-r5465:HEAD from branch/iola/shimfree). Copying relevant commit messages here: - Deleted dead code in many places. - Renamed id-something to draft-something, make the "is this eligible for expiration" logic clearer - Added a name for IPR search URL - Revamped the ballot popup view - URL reversed the IPR search link instead of hardcoding it - Cleaned up search views and remove dead code, port them to the new DB schema, hack related views in iesg/ and wginfo/ to use the new search interfaces, avoid camelCase in search GET parameters (with backwards-compat fallback), add some simple search unit tests, remove caching from views_search.py index pages as they're now pretty fast to generate, rewrite ballot popup JS, regularize some CSS classes to use hyphen-notation rather than camelCase, move some of the search templates to doc/. idrfc/ now mostly contains some wrapper code still in use by other subdirs, some ported code not yet moved, and dead code. - Fixed output bug in test crawler and print referrer upon errors so it's easier to figure out where a link came from - Added /doc/in-last-call/ to crawler, report original page as referrer in a redirect chain rather than intermediate URL - Ported idindex to new schema, speed them up, add tests, refactor index page in views_search to share code with the text index file, get rid of some special-case idindex filters from ietf_filters, move "/drafts/" redirects to a file in /doc/ - Ported /idtracker/status/ and /idtracker/status/last-call/ overview of drafts in IESG process to new schema in /doc/iesg/ and /doc/iesg/last-call/ - Added redirects for all of /idtracker/*, removed all view code and other dead code from idtracker/ - Removed the idtracker sitemap indexing drafts - in its current form, it adds nothing of value to the HTML-based /doc/all/ view, and it's pretty slow - Ported idtracker feeds to new schema, move them to doc/, cleaned up idtracker/ - only templatetags/ietf_filters and proxy code is left - Legacy-Id: 5836
This commit is contained in:
commit
cbfe489ff5
|
@ -231,7 +231,7 @@ Regards,
|
|||
Henrik
|
||||
(via the mkrelease script)
|
||||
" > ~/src/db/release-mail-v$VER.txt
|
||||
cat ~/src/db/release-mail-v$VER.txt | $do mail -s "New datatracker release: v$VER" -c henrik@levkowetz.com -c glen@amsl.com -c fenner@fenron.net -c rjs@nostrum.com -c housley@vigilsec.com -c cmorgan@amsl.com -c avezza@amsl.com -c amorris@amsl.com -c smccammon@amsl.com -c kmoreland@amsl.com -c stevey@amsl.com -c wchen@amsl.com -c olau@iola.dk $contributors codesprints@ietf.org
|
||||
cat ~/src/db/release-mail-v$VER.txt | $do mail -s "New datatracker release: v$VER" -c henrik@levkowetz.com -c glen@amsl.com -c fenner@fenron.net -c rjs@nostrum.com -c housley@vigilsec.com -c cmorgan@amsl.com -c avezza@amsl.com -c amorris@amsl.com -c smccammon@amsl.com -c kmoreland@amsl.com -c stevey@amsl.com -c olau@iola.dk $contributors codesprints@ietf.org
|
||||
|
||||
$do toolsfeed control changelog /www/tools.ietf.org/tools/atomfeed.xml
|
||||
$do toolpush /www/tools.ietf.org/tools/atomfeed.xml
|
||||
|
|
|
@ -11,10 +11,11 @@ syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_USER)
|
|||
|
||||
from ietf.idrfc.expire import *
|
||||
|
||||
if not in_id_expire_freeze():
|
||||
for doc in get_expired_ids():
|
||||
send_expire_notice_for_id(doc)
|
||||
expire_id(doc)
|
||||
syslog.syslog("Expired %s (id=%s)%s" % (doc.file_tag(), doc.pk, " in the ID Tracker" if doc.latest_event(type="started_iesg_process") else ""))
|
||||
if not in_draft_expire_freeze():
|
||||
for doc in get_expired_drafts():
|
||||
send_expire_notice_for_draft(doc)
|
||||
expire_draft(doc)
|
||||
syslog.syslog("Expired draft %s-%s" % (doc.name, doc.rev))
|
||||
|
||||
clean_up_id_files()
|
||||
syslog.syslog("Cleaning up draft files")
|
||||
clean_up_draft_files()
|
||||
|
|
|
@ -6,11 +6,11 @@ from ietf import settings
|
|||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
from ietf.idrfc.expire import get_soon_to_expire_ids, send_expire_warning_for_id
|
||||
from ietf.idrfc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft
|
||||
|
||||
|
||||
# notify about documents that expire within the next 2 weeks
|
||||
notify_days = 14
|
||||
notify_days = 14
|
||||
|
||||
for doc in get_soon_to_expire_ids(notify_days):
|
||||
send_expire_warning_for_id(doc)
|
||||
for doc in get_soon_to_expire_drafts(notify_days):
|
||||
send_expire_warning_for_draft(doc)
|
||||
|
|
|
@ -24,6 +24,12 @@ connection.queries = DontSaveQueries()
|
|||
MAX_URL_LENGTH = 500
|
||||
SLOW_THRESHOLD = 1.0
|
||||
|
||||
initial = ["/doc/all/", "/doc/in-last-call/"]
|
||||
|
||||
visited = set()
|
||||
urls = {} # url -> referrer
|
||||
|
||||
|
||||
def strip_url(url):
|
||||
if url.startswith("http://testserver"):
|
||||
url = url[len("http://testserver"):]
|
||||
|
@ -40,15 +46,13 @@ def extract_html_urls(content):
|
|||
|
||||
yield url
|
||||
|
||||
|
||||
visited = set()
|
||||
blacklist = set()
|
||||
urls = set(["/doc/all/"])
|
||||
|
||||
client = django.test.Client()
|
||||
|
||||
for url in initial:
|
||||
urls[url] = "[initial]"
|
||||
|
||||
while urls:
|
||||
url = urls.pop()
|
||||
url, referrer = urls.popitem()
|
||||
|
||||
visited.add(url)
|
||||
|
||||
|
@ -62,7 +66,7 @@ while urls:
|
|||
except:
|
||||
print "FAIL", url
|
||||
print "============="
|
||||
traceback.print_exc()
|
||||
print traceback.format_exc()
|
||||
print "============="
|
||||
else:
|
||||
tags = []
|
||||
|
@ -70,7 +74,7 @@ while urls:
|
|||
if r.status_code in (301, 302):
|
||||
u = strip_url(r["Location"])
|
||||
if u not in visited and u not in urls:
|
||||
urls.add(u)
|
||||
urls[u] = referrer # referrer is original referrer, not redirected url
|
||||
|
||||
elif r.status_code == 200:
|
||||
ctype = r["Content-Type"]
|
||||
|
@ -80,9 +84,9 @@ while urls:
|
|||
if ctype == "text/html":
|
||||
for u in extract_html_urls(r.content):
|
||||
if u not in visited and u not in urls:
|
||||
urls.add(u)
|
||||
urls[u] = url
|
||||
else:
|
||||
tags.append("FAIL")
|
||||
tags.append(u"FAIL (from %s)" % referrer)
|
||||
|
||||
if elapsed.total_seconds() > SLOW_THRESHOLD:
|
||||
tags.append("SLOW")
|
||||
|
|
86
ietf/doc/feeds.py
Normal file
86
ietf/doc/feeds.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
import datetime, re
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
|
||||
from django.utils.feedgenerator import Atom1Feed
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.template.defaultfilters import truncatewords_html, date as datefilter, linebreaks
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.text import truncate_words
|
||||
|
||||
from ietf.doc.models import *
|
||||
from ietf.doc.utils import augment_events_with_revision
|
||||
from ietf.idtracker.templatetags.ietf_filters import format_textarea
|
||||
|
||||
class DocumentChanges(Feed):
|
||||
feed_type = Atom1Feed
|
||||
|
||||
def get_object(self, bits):
|
||||
if len(bits) != 1:
|
||||
raise Document.DoesNotExist
|
||||
|
||||
return Document.objects.get(docalias__name=bits[0])
|
||||
|
||||
def title(self, obj):
|
||||
return "Changes for %s" % obj.display_name()
|
||||
|
||||
def link(self, obj):
|
||||
if obj is None:
|
||||
raise FeedDoesNotExist
|
||||
if not hasattr(self, "cached_link"):
|
||||
self.cached_link = urlreverse("doc_history", kwargs=dict(name=obj.canonical_name()))
|
||||
return self.cached_link
|
||||
|
||||
def subtitle(self, obj):
|
||||
return "History of change entries for %s." % obj.display_name()
|
||||
|
||||
def items(self, obj):
|
||||
events = obj.docevent_set.all().order_by("-time","-id")
|
||||
augment_events_with_revision(obj, events)
|
||||
return events
|
||||
|
||||
def item_title(self, item):
|
||||
return u"[%s] %s [rev. %s]" % (item.by, truncate_words(strip_tags(item.desc), 15), item.rev)
|
||||
|
||||
def item_description(self, item):
|
||||
return truncatewords_html(format_textarea(item.desc), 20)
|
||||
|
||||
def item_pubdate(self, item):
|
||||
return item.time
|
||||
|
||||
def item_author_name(self, item):
|
||||
return unicode(item.by)
|
||||
|
||||
def item_link(self, item):
|
||||
return self.cached_link + "#history-%s" % item.pk
|
||||
|
||||
class InLastCall(Feed):
|
||||
title = "Documents in Last Call"
|
||||
subtitle = "Announcements for documents in last call."
|
||||
feed_type = Atom1Feed
|
||||
author_name = 'IESG Secretary'
|
||||
link = "/doc/iesg/last-call/"
|
||||
|
||||
def items(self):
|
||||
docs = list(Document.objects.filter(type="draft", states=State.objects.get(type="draft-iesg", slug="lc")))
|
||||
for d in docs:
|
||||
d.lc_event = d.latest_event(LastCallDocEvent, type="sent_last_call")
|
||||
|
||||
docs = [d for d in docs if d.lc_event]
|
||||
docs.sort(key=lambda d: d.lc_event.expires)
|
||||
|
||||
return docs
|
||||
|
||||
def item_title(self, item):
|
||||
return u"%s (%s - %s)" % (item.name,
|
||||
datefilter(item.lc_event.time, "F j"),
|
||||
datefilter(item.lc_event.expires, "F j, Y"))
|
||||
|
||||
def item_description(self, item):
|
||||
return linebreaks(item.lc_event.desc)
|
||||
|
||||
def item_pubdate(self, item):
|
||||
return item.lc_event.time
|
||||
|
|
@ -37,6 +37,9 @@ class State(models.Model):
|
|||
class Meta:
|
||||
ordering = ["type", "order"]
|
||||
|
||||
IESG_BALLOT_ACTIVE_STATES = ("lc", "writeupw", "goaheadw", "iesg-eva", "defer")
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
|
||||
class DocumentInfo(models.Model):
|
||||
"""Any kind of document. Draft, RFC, Charter, IPR Statement, Liaison Statement"""
|
||||
time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True
|
||||
|
@ -186,9 +189,7 @@ class Document(DocumentInfo):
|
|||
def get_absolute_url(self):
|
||||
name = self.name
|
||||
if self.type_id == "draft" and self.get_state_slug() == "rfc":
|
||||
aliases = self.docalias_set.filter(name__startswith="rfc")
|
||||
if aliases:
|
||||
name = aliases[0].name
|
||||
name = self.canonical_name()
|
||||
elif self.type_id in ('slides','agenda','minutes'):
|
||||
session = self.session_set.all()[0]
|
||||
meeting = session.meeting
|
||||
|
@ -260,11 +261,10 @@ class Document(DocumentInfo):
|
|||
raise TypeError("Expected a string, tuple or list, received %s" % type(relationship))
|
||||
return DocAlias.objects.filter(relateddocument__source=self, relateddocument__relationship__in=relationship)
|
||||
|
||||
#TODO can/should this be a function instead of a property? Currently a view uses it as a property
|
||||
@property
|
||||
def telechat_date(self):
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return e.telechat_date if e else None
|
||||
def telechat_date(self, e=None):
|
||||
if not e:
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return e.telechat_date if e and e.telechat_date and e.telechat_date >= datetime.date.today() else None
|
||||
|
||||
def area_acronym(self):
|
||||
g = self.group
|
||||
|
@ -283,10 +283,6 @@ class Document(DocumentInfo):
|
|||
else:
|
||||
return "none"
|
||||
|
||||
def on_upcoming_agenda(self):
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return bool(e and e.telechat_date and e.telechat_date >= datetime.date.today())
|
||||
|
||||
def returning_item(self):
|
||||
e = self.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
return e.returning_item if e else None
|
||||
|
@ -311,56 +307,56 @@ class Document(DocumentInfo):
|
|||
return '<a href="%s">%s-%s</a>' % (self.get_absolute_url(), self.name , self.rev)
|
||||
|
||||
def rfc_number(self):
|
||||
qs = self.docalias_set.filter(name__startswith='rfc')
|
||||
return qs[0].name[3:] if qs else None
|
||||
n = self.canonical_name()
|
||||
return n[3:] if n.startswith("rfc") else None
|
||||
|
||||
def friendly_state(self):
|
||||
""" Return a concise text description of the document's current state """
|
||||
if self.type_id=='draft':
|
||||
# started_iesg_process is is how the redesigned database schema (as of May2012) captured what
|
||||
# used to be "has an IDInternal", aka *Wrapper.in_ietf_process()=True
|
||||
in_iesg_process = self.latest_event(type='started_iesg_process')
|
||||
iesg_state_summary=None
|
||||
if in_iesg_process:
|
||||
iesg_state = self.states.get(type='draft-iesg')
|
||||
""" Return a concise text description of the document's current state."""
|
||||
state = self.get_state()
|
||||
if not state:
|
||||
return "Unknown state"
|
||||
|
||||
if self.type_id == 'draft':
|
||||
iesg_state = self.get_state("draft-iesg")
|
||||
iesg_state_summary = None
|
||||
if iesg_state:
|
||||
# This knowledge about which tags are reportable IESG substate tags is duplicated in idrfc
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
iesg_substate = self.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
# There really shouldn't be more than one tag in iesg_substate, but this will do something sort-of-sensible if there is
|
||||
iesg_state_summary = iesg_state.name
|
||||
if iesg_substate:
|
||||
iesg_state_summary = iesg_state_summary + "::"+"::".join(tag.name for tag in iesg_substate)
|
||||
|
||||
if self.get_state_slug() == "rfc":
|
||||
n = self.rfc_number()
|
||||
return "<a href=\"%s\">RFC %s</a>" % (urlreverse('doc_view', kwargs=dict(name='rfc%s' % n)), n)
|
||||
elif self.get_state_slug() == "repl":
|
||||
if state.slug == "rfc":
|
||||
return "RFC %s (%s)" % (self.rfc_number(), self.std_level)
|
||||
elif state.slug == "repl":
|
||||
rs = self.related_that("replaces")
|
||||
if rs:
|
||||
return mark_safe("Replaced by " + ", ".join("<a href=\"%s\">%s</a>" % (urlreverse('doc_view', args=[name]), name) for name in rs))
|
||||
return mark_safe("Replaced by " + ", ".join("<a href=\"%s\">%s</a>" % (urlreverse('doc_view', kwargs=dict(name=name)), name) for name in rs))
|
||||
else:
|
||||
return "Replaced"
|
||||
elif self.get_state_slug() == "active":
|
||||
if in_iesg_process:
|
||||
elif state.slug == "active":
|
||||
if iesg_state:
|
||||
if iesg_state.slug == "dead":
|
||||
# Many drafts in the draft-iesg "Dead" state are not dead
|
||||
# in other state machines; they're just not currently under
|
||||
# IESG processing. Show them as "I-D Exists (IESG: Dead)" instead...
|
||||
return "I-D Exists (IESG: "+iesg_state_summary+")"
|
||||
return "I-D Exists (IESG: %s)" % iesg_state_summary
|
||||
elif iesg_state.slug == "lc":
|
||||
expiration_date = str(self.latest_event(LastCallDocEvent,type="sent_last_call").expires.date())
|
||||
return iesg_state_summary + " (ends "+expiration_date+")"
|
||||
else:
|
||||
return iesg_state_summary
|
||||
e = self.latest_event(LastCallDocEvent, type="sent_last_call")
|
||||
if e:
|
||||
return iesg_state_summary + " (ends %s)" % e.expires.date().isoformat()
|
||||
|
||||
return iesg_state_summary
|
||||
else:
|
||||
return "I-D Exists"
|
||||
else:
|
||||
if in_iesg_process and iesg_state.slug == "dead":
|
||||
return self.get_state().name +" (IESG: "+iesg_state_summary+")"
|
||||
if iesg_state and iesg_state.slug == "dead":
|
||||
return state.name + " (IESG: %s)" % iesg_state_summary
|
||||
# Expired/Withdrawn by Submitter/IETF
|
||||
return self.get_state().name
|
||||
return state.name
|
||||
else:
|
||||
return self.get_state().name
|
||||
return state.name
|
||||
|
||||
def ipr(self):
|
||||
"""Returns the IPR disclosures against this document (as a queryset over IprDocAlias)."""
|
||||
|
|
23
ietf/doc/redirect_drafts_urls.py
Normal file
23
ietf/doc/redirect_drafts_urls.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls.defaults import patterns
|
||||
|
||||
|
||||
from django.http import HttpResponsePermanentRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from ietf.group.models import Group
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/'}),
|
||||
(r'^all/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/all/'}),
|
||||
(r'^rfc/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/all/#rfc'}),
|
||||
(r'^dead/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/all/#expired'}),
|
||||
(r'^current/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/active/'}),
|
||||
(r'^(?P<object_id>\d+)/(related/)?$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/' }),
|
||||
(r'^(?P<name>[^/]+)/(related/)?$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/%(name)s/' }),
|
||||
(r'^wgid/(?P<id>\d+)/$', lambda request, id: HttpResponsePermanentRedirect("/wg/%s/" % get_object_or_404(Group, id=id).acronym)),
|
||||
(r'^wg/(?P<acronym>[^/]+)/$', 'django.views.generic.simple.redirect_to', { 'url': '/wg/%(acronym)s/' }),
|
||||
(r'^all_id(?:_txt)?.html$', 'django.views.generic.simple.redirect_to', { 'url': 'http://www.ietf.org/id/all_id.txt' }),
|
||||
)
|
13
ietf/doc/redirect_idtracker_urls.py
Normal file
13
ietf/doc/redirect_idtracker_urls.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
from django.views.generic.simple import redirect_to
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^help/(?:sub)?state/(?:\d+/)?$', redirect_to, {'url': '/doc/help/state/draft-iesg/' }),
|
||||
(r'^help/evaluation/$', redirect_to, {'url':'http://www.ietf.org/iesg/voting-procedures.html' }),
|
||||
(r'^status/$', redirect_to, {'url':'/doc/iesg/' }),
|
||||
(r'^status/last-call/$', redirect_to, {'url':'/doc/iesg/last-call/' }),
|
||||
(r'^rfc0*(?P<rfc_number>\d+)/$', redirect_to, {'url':'/doc/rfc%(rfc_number)s/' }),
|
||||
(r'^(?P<name>[^/]+)/$', redirect_to, {'url':'/doc/%(name)s/' }),
|
||||
(r'^(?P<name>[^/]+)/comment/\d+/$', redirect_to, {'url':'/doc/%(name)s/history/' }),
|
||||
(r'^$', redirect_to, { 'url': '/doc/'}),
|
||||
)
|
|
@ -2,7 +2,6 @@ import os, shutil, datetime
|
|||
|
||||
import django.test
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.conf import settings
|
||||
|
||||
from pyquery import PyQuery
|
||||
|
||||
|
@ -21,6 +20,108 @@ from ietf.iesg.models import TelechatDate
|
|||
from ietf.doc.tests_conflict_review import *
|
||||
|
||||
|
||||
class SearchTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def test_search(self):
|
||||
draft = make_test_data()
|
||||
|
||||
base_url = urlreverse("doc_search")
|
||||
|
||||
# only show form, no search yet
|
||||
r = self.client.get(base_url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# no match
|
||||
r = self.client.get(base_url + "?activedrafts=on&name=thisisnotadocumentname")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("no documents match" in str(r.content).lower())
|
||||
|
||||
r = self.client.get(base_url + "?rfcs=on&name=xyzzy")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("no documents match" in r.content.lower())
|
||||
|
||||
r = self.client.get(base_url + "?olddrafts=on&name=")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue("no documents match" in r.content.lower())
|
||||
|
||||
# find by rfc/active/inactive
|
||||
draft.set_state(State.objects.get(type="draft", slug="rfc"))
|
||||
r = self.client.get(base_url + "?rfcs=on&name=%s" % draft.name)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
r = self.client.get(base_url + "?activedrafts=on&name=%s" % draft.name)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="expired"))
|
||||
r = self.client.get(base_url + "?olddrafts=on&name=%s" % draft.name)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
|
||||
# find by title
|
||||
r = self.client.get(base_url + "?activedrafts=on&name=%s" % draft.title.split()[0])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by author
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=author&author=%s" % draft.authors.all()[0].person.name_parts()[1])
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by group
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=group&group=%s" % draft.group.acronym)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by area
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=area&area=%s" % draft.group.parent_id)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by area
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=area&area=%s" % draft.group.parent_id)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by AD
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=ad&ad=%s" % draft.ad_id)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
# find by IESG state
|
||||
r = self.client.get(base_url + "?activedrafts=on&by=state&state=%s&substate=" % draft.get_state("draft-iesg").pk)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
def test_drafts_pages(self):
|
||||
draft = make_test_data()
|
||||
|
||||
r = self.client.get(urlreverse("drafts_for_ad", kwargs=dict(name=draft.ad.full_name_as_key())))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="lc"))
|
||||
r = self.client.get(urlreverse("drafts_in_last_call"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
def test_indexes(self):
|
||||
draft = make_test_data()
|
||||
|
||||
r = self.client.get(urlreverse("index_all_drafts"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.name in r.content)
|
||||
|
||||
r = self.client.get(urlreverse("index_active_drafts"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(draft.title in r.content)
|
||||
|
||||
|
||||
class DocTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
|
@ -134,7 +235,7 @@ class DocTestCase(django.test.TestCase):
|
|||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
# test popup too while we're at it
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.ballot_for_popup", kwargs=dict(name=doc.name)))
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.ballot_popup", kwargs=dict(name=doc.name, ballot_id=ballot.pk)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_document_json(self):
|
||||
|
|
|
@ -222,7 +222,7 @@ def document_main(request, name, rev=None):
|
|||
|
||||
# ballot
|
||||
ballot_summary = None
|
||||
if iesg_state and iesg_state.slug in ("lc", "writeupw", "goaheadw", "iesg-eva", "defer"):
|
||||
if iesg_state and iesg_state.slug in IESG_BALLOT_ACTIVE_STATES:
|
||||
active_ballot = doc.active_ballot()
|
||||
if active_ballot:
|
||||
ballot_summary = needed_ballot_positions(doc, active_ballot.active_ad_positions().values())
|
||||
|
@ -653,6 +653,17 @@ def document_ballot(request, name, ballot_id=None):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def ballot_popup(request, name, ballot_id):
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
c = document_ballot_content(request, doc, ballot_id=ballot_id, editable=False)
|
||||
return render_to_response("doc/ballot_popup.html",
|
||||
dict(doc=doc,
|
||||
ballot_content=c,
|
||||
ballot_id=ballot_id,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def document_json(request, name):
|
||||
doc = get_object_or_404(Document, docalias__name=name)
|
||||
|
||||
|
@ -699,11 +710,6 @@ def document_json(request, name):
|
|||
|
||||
return HttpResponse(json.dumps(data, indent=2), mimetype='text/plain')
|
||||
|
||||
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_json(request, name):
|
||||
# REDESIGN: this view needs to be deleted or updated
|
||||
def get_ballot(name):
|
||||
|
|
45
ietf/doc/views_help.py
Normal file
45
ietf/doc/views_help.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
from django import forms
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.template import RequestContext
|
||||
|
||||
from ietf.doc.models import *
|
||||
|
||||
def state_help(request, type):
|
||||
slug, title = {
|
||||
"draft-iesg": ("draft-iesg", "IESG States For Internet-Drafts"),
|
||||
"draft-rfceditor": ("draft-rfceditor", "RFC Editor States For Internet-Drafts"),
|
||||
"draft-iana-action": ("draft-iana-action", "IANA Action States For Internet-Drafts"),
|
||||
"charter": ("charter", "Charter States"),
|
||||
"conflict-review": ("conflrev", "Conflict Review States")
|
||||
}.get(type, "")
|
||||
state_type = get_object_or_404(StateType, slug=slug)
|
||||
|
||||
states = State.objects.filter(type=state_type).order_by("order")
|
||||
|
||||
has_next_states = False
|
||||
for state in states:
|
||||
if state.next_states.all():
|
||||
has_next_states = True
|
||||
break
|
||||
|
||||
tags = []
|
||||
|
||||
if state_type.slug == "draft-iesg":
|
||||
# legacy hack
|
||||
states = list(states)
|
||||
fake_state = dict(name="I-D Exists",
|
||||
desc="Initial (default) state for all internet drafts. Such documents are not being tracked by the IESG as no request has been made of the IESG to do anything with the document.",
|
||||
next_states=dict(all=State.objects.filter(type="draft-iesg", slug__in=("watching", "pub-req")))
|
||||
)
|
||||
states.insert(0, fake_state)
|
||||
|
||||
tags = DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
|
||||
return render_to_response("doc/state_help.html", {
|
||||
"title": title,
|
||||
"state_type": state_type,
|
||||
"states": states,
|
||||
"has_next_states": has_next_states,
|
||||
"tags": tags,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
|
@ -34,5 +34,5 @@ from ietf import settings
|
|||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
from ietf.idindex.views import all_id2_txt
|
||||
from ietf.idindex.index import all_id2_txt
|
||||
print all_id2_txt().encode('utf-8'),
|
||||
|
|
|
@ -34,5 +34,5 @@ from ietf import settings
|
|||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
from ietf.idindex.views import all_id_txt
|
||||
print all_id_txt(),
|
||||
from ietf.idindex.index import all_id_txt
|
||||
print all_id_txt().encode("utf-8"),
|
||||
|
|
|
@ -34,9 +34,5 @@ from ietf import settings
|
|||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
from ietf.idindex.views import id_abstracts_txt
|
||||
x = id_abstracts_txt()
|
||||
if isinstance(x, unicode):
|
||||
print x.encode('utf-8'),
|
||||
else:
|
||||
print x,
|
||||
from ietf.idindex.index import id_index_txt
|
||||
print id_index_txt(with_abstracts=True).encode('utf-8'),
|
||||
|
|
|
@ -34,9 +34,5 @@ from ietf import settings
|
|||
from django.core import management
|
||||
management.setup_environ(settings)
|
||||
|
||||
from ietf.idindex.views import id_index_txt
|
||||
x = id_index_txt()
|
||||
if isinstance(x, unicode):
|
||||
print x.encode('utf-8'),
|
||||
else:
|
||||
print x,
|
||||
from ietf.idindex.index import id_index_txt
|
||||
print id_index_txt().encode('utf-8'),
|
||||
|
|
275
ietf/idindex/index.py
Normal file
275
ietf/idindex/index.py
Normal file
|
@ -0,0 +1,275 @@
|
|||
# code to generate plain-text index files that are placed on
|
||||
# www.ietf.org in the same directory as the I-Ds
|
||||
|
||||
import datetime, os
|
||||
|
||||
import pytz
|
||||
|
||||
from django.conf import settings
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from ietf.idtracker.templatetags.ietf_filters import clean_whitespace
|
||||
from ietf.doc.models import *
|
||||
|
||||
def all_id_txt():
|
||||
# this returns a lot of data so try to be efficient
|
||||
|
||||
# precalculations
|
||||
revision_time = dict(NewRevisionDocEvent.objects.filter(type="new_revision", doc__name__startswith="draft-").order_by('time').values_list("doc_id", "time"))
|
||||
|
||||
def formatted_rev_date(name):
|
||||
t = revision_time.get(name)
|
||||
return t.strftime("%Y-%m-%d") if t else ""
|
||||
|
||||
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
|
||||
document__states=State.objects.get(type="draft", slug="rfc")).values_list("document_id", "name"))
|
||||
|
||||
replacements = dict(RelatedDocument.objects.filter(target__document__states=State.objects.get(type="draft", slug="repl"),
|
||||
relationship="replaces").values_list("target__document_id", "source"))
|
||||
|
||||
|
||||
# we need a distinct to prevent the queries below from multiplying the result
|
||||
all_ids = Document.objects.filter(type="draft").order_by('name').exclude(name__startswith="rfc").distinct()
|
||||
|
||||
res = ["\nInternet-Drafts Status Summary\n"]
|
||||
|
||||
def add_line(f1, f2, f3, f4):
|
||||
# each line must have exactly 4 tab-separated fields
|
||||
res.append(f1 + "\t" + f2 + "\t" + f3 + "\t" + f4)
|
||||
|
||||
|
||||
inactive_states = ["pub", "watching", "dead"]
|
||||
|
||||
in_iesg_process = all_ids.exclude(states=State.objects.get(type="draft", slug="rfc")).filter(states__in=list(State.objects.filter(type="draft-iesg").exclude(slug__in=inactive_states))).only("name", "rev")
|
||||
|
||||
# handle those actively in the IESG process
|
||||
for d in in_iesg_process:
|
||||
state = d.get_state("draft-iesg").name
|
||||
tags = d.tags.filter(slug__in=IESG_SUBSTATE_TAGS).values_list("name", flat=True)
|
||||
if tags:
|
||||
state += "::" + "::".join(tags)
|
||||
add_line(d.name + "-" + d.rev,
|
||||
formatted_rev_date(d.name),
|
||||
"In IESG processing - ID Tracker state <" + state + ">",
|
||||
"",
|
||||
)
|
||||
|
||||
|
||||
# handle the rest
|
||||
|
||||
not_in_process = all_ids.exclude(pk__in=[d.name for d in in_iesg_process])
|
||||
|
||||
for s in State.objects.filter(type="draft").order_by("order"):
|
||||
for name, rev in not_in_process.filter(states=s).values_list("name", "rev"):
|
||||
state = s.name
|
||||
last_field = ""
|
||||
|
||||
if s.slug == "rfc":
|
||||
a = rfc_aliases.get(name)
|
||||
if a:
|
||||
last_field = a[3:]
|
||||
elif s.slug == "repl":
|
||||
state += " replaced by " + replacements.get(name, "0")
|
||||
|
||||
add_line(name + "-" + rev,
|
||||
formatted_rev_date(name),
|
||||
state,
|
||||
last_field,
|
||||
)
|
||||
|
||||
return u"\n".join(res) + "\n"
|
||||
|
||||
def file_types_for_drafts():
|
||||
"""Look in the draft directory and return file types found as dict (name + rev -> [t1, t2, ...])."""
|
||||
file_types = {}
|
||||
for filename in os.listdir(settings.INTERNET_DRAFT_PATH):
|
||||
if filename.startswith("draft-"):
|
||||
base, ext = os.path.splitext(filename)
|
||||
if ext:
|
||||
if base not in file_types:
|
||||
file_types[base] = [ext]
|
||||
else:
|
||||
file_types[base].append(ext)
|
||||
|
||||
return file_types
|
||||
|
||||
def all_id2_txt():
|
||||
# this returns a lot of data so try to be efficient
|
||||
|
||||
drafts = Document.objects.filter(type="draft").exclude(name__startswith="rfc").order_by('name').select_related('group', 'group__parent', 'ad', 'ad__email', 'intended_std_level', 'shepherd', 'shepherd__email')
|
||||
|
||||
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
|
||||
document__states=State.objects.get(type="draft", slug="rfc")).values_list("document_id", "name"))
|
||||
|
||||
replacements = dict(RelatedDocument.objects.filter(target__document__states=State.objects.get(type="draft", slug="repl"),
|
||||
relationship="replaces").values_list("target__document_id", "source"))
|
||||
|
||||
revision_time = dict(DocEvent.objects.filter(type="new_revision", doc__name__startswith="draft-").order_by('time').values_list("doc_id", "time"))
|
||||
|
||||
file_types = file_types_for_drafts()
|
||||
|
||||
authors = {}
|
||||
for a in DocumentAuthor.objects.filter(document__name__startswith="draft-").order_by("order").select_related("author", "author__person").iterator():
|
||||
if a.document_id not in authors:
|
||||
l = authors[a.document_id] = []
|
||||
else:
|
||||
l = authors[a.document_id]
|
||||
if "@" in a.author.address:
|
||||
l.append(u'%s <%s>' % (a.author.person.plain_name().replace("@", ""), a.author.address.replace(",", "")))
|
||||
else:
|
||||
l.append(a.author.person.plain_name())
|
||||
|
||||
res = []
|
||||
for d in drafts:
|
||||
state = d.get_state_slug()
|
||||
iesg_state = d.get_state("draft-iesg")
|
||||
|
||||
fields = []
|
||||
# 0
|
||||
fields.append(d.name + "-" + d.rev)
|
||||
# 1
|
||||
fields.append("-1") # used to be internal numeric identifier, we don't have that anymore
|
||||
# 2
|
||||
fields.append(d.get_state().name if state else "")
|
||||
# 3
|
||||
if state == "active":
|
||||
s = "I-D Exists"
|
||||
if iesg_state:
|
||||
s = iesg_state.name
|
||||
tags = d.tags.filter(slug__in=IESG_SUBSTATE_TAGS).values_list("name", flat=True)
|
||||
if tags:
|
||||
s += "::" + "::".join(tags)
|
||||
fields.append(s)
|
||||
else:
|
||||
fields.append("")
|
||||
# 4
|
||||
rfc_number = ""
|
||||
if state == "rfc":
|
||||
a = rfc_aliases.get(d.name)
|
||||
if a:
|
||||
rfc_number = a[3:]
|
||||
fields.append(rfc_number)
|
||||
# 5
|
||||
repl = ""
|
||||
if state == "repl":
|
||||
repl = replacements.get(d.name, "")
|
||||
fields.append(repl)
|
||||
# 6
|
||||
t = revision_time.get(d.name)
|
||||
fields.append(t.strftime("%Y-%m-%d") if t else "")
|
||||
# 7
|
||||
group_acronym = ""
|
||||
if d.group and d.group.type_id != "area" and d.group.acronym != "none":
|
||||
group_acronym = d.group.acronym
|
||||
fields.append(group_acronym)
|
||||
# 8
|
||||
area = ""
|
||||
if d.group:
|
||||
if d.group.type_id == "area":
|
||||
area = d.group.acronym
|
||||
elif d.group.type_id == "wg" and d.group.parent and d.group.parent.type_id == "area":
|
||||
area = d.group.parent.acronym
|
||||
fields.append(area)
|
||||
# 9 responsible AD name
|
||||
fields.append(unicode(d.ad) if d.ad else "")
|
||||
# 10
|
||||
fields.append(d.intended_std_level.name if d.intended_std_level else "")
|
||||
# 11
|
||||
lc_expires = ""
|
||||
if iesg_state and iesg_state.slug == "lc":
|
||||
e = d.latest_event(LastCallDocEvent, type="sent_last_call")
|
||||
if e:
|
||||
lc_expires = e.expires.strftime("%Y-%m-%d")
|
||||
fields.append(lc_expires)
|
||||
# 12
|
||||
doc_file_types = file_types.get(d.name + "-" + d.rev, [])
|
||||
doc_file_types.sort() # make the order consistent (and the result testable)
|
||||
fields.append(",".join(doc_file_types) if state == "active" else "")
|
||||
# 13
|
||||
fields.append(clean_whitespace(d.title)) # FIXME: we should make sure this is okay in the database and in submit
|
||||
# 14
|
||||
fields.append(u", ".join(authors.get(d.name, [])))
|
||||
# 15
|
||||
fields.append(d.shepherd.formatted_email().replace('"', '') if d.shepherd else "")
|
||||
# 16 Responsible AD name and email
|
||||
fields.append(d.ad.formatted_email().replace('"', '') if d.ad else "")
|
||||
|
||||
#
|
||||
res.append(u"\t".join(fields))
|
||||
|
||||
return render_to_string("idindex/all_id2.txt", {'data': u"\n".join(res) })
|
||||
|
||||
def active_drafts_index_by_group(extra_values=()):
|
||||
"""Return active drafts grouped into their corresponding
|
||||
associated group, for spitting out draft index."""
|
||||
|
||||
# this returns a lot of data so try to be efficient
|
||||
|
||||
active_state = State.objects.get(type="draft", slug="active")
|
||||
|
||||
groups_dict = dict((g.id, g) for g in Group.objects.all())
|
||||
|
||||
extracted_values = ("name", "rev", "title", "group_id") + extra_values
|
||||
|
||||
docs_dict = dict((d["name"], d)
|
||||
for d in Document.objects.filter(states=active_state).values(*extracted_values))
|
||||
|
||||
# add initial and latest revision time
|
||||
for time, doc_id in NewRevisionDocEvent.objects.filter(type="new_revision", doc__states=active_state).order_by('-time').values_list("time", "doc_id"):
|
||||
d = docs_dict.get(doc_id)
|
||||
if d:
|
||||
if "rev_time" not in d:
|
||||
d["rev_time"] = time
|
||||
d["initial_rev_time"] = time
|
||||
|
||||
# add authors
|
||||
for a in DocumentAuthor.objects.filter(document__states=active_state).order_by("order").select_related("author__person"):
|
||||
d = docs_dict.get(a.document_id)
|
||||
if d:
|
||||
if "authors" not in d:
|
||||
d["authors"] = []
|
||||
d["authors"].append(unicode(a.author.person))
|
||||
|
||||
# put docs into groups
|
||||
for d in docs_dict.itervalues():
|
||||
g = groups_dict.get(d["group_id"])
|
||||
if not g:
|
||||
continue
|
||||
|
||||
if not hasattr(g, "active_drafts"):
|
||||
g.active_drafts = []
|
||||
|
||||
g.active_drafts.append(d)
|
||||
|
||||
groups = [g for g in groups_dict.itervalues() if hasattr(g, "active_drafts")]
|
||||
groups.sort(key=lambda g: g.acronym)
|
||||
|
||||
fallback_time = datetime.datetime(1950, 1, 1)
|
||||
for g in groups:
|
||||
g.active_drafts.sort(key=lambda d: d.get("initial_rev_time", fallback_time))
|
||||
|
||||
return groups
|
||||
|
||||
def id_index_txt(with_abstracts=False):
|
||||
extra_values = ()
|
||||
if with_abstracts:
|
||||
extra_values = ("abstract",)
|
||||
groups = active_drafts_index_by_group(extra_values)
|
||||
|
||||
file_types = file_types_for_drafts()
|
||||
for g in groups:
|
||||
for d in g.active_drafts:
|
||||
# we need to output a multiple extension thing
|
||||
types = file_types.get(d["name"] + "-" + d["rev"], "")
|
||||
exts = ".txt"
|
||||
if ".ps" in types:
|
||||
exts += ",.ps"
|
||||
if ".pdf" in types:
|
||||
exts += ",.pdf"
|
||||
d["exts"] = exts
|
||||
|
||||
return render_to_string("idindex/id_index.txt", {
|
||||
'groups': groups,
|
||||
'time': datetime.datetime.now(pytz.UTC).strftime("%Y-%m-%d %H:%M:%S %Z"),
|
||||
'with_abstracts': with_abstracts,
|
||||
})
|
|
@ -1 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
|
@ -1,72 +1,146 @@
|
|||
# Copyright (C) 2009 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 datetime, shutil
|
||||
|
||||
import unittest
|
||||
import re
|
||||
from django.test.client import Client
|
||||
from ietf.utils.test_utils import SimpleUrlTestCase, RealDatabaseTest
|
||||
import django.test
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
class IdIndexUrlTestCase(SimpleUrlTestCase):
|
||||
def testUrls(self):
|
||||
self.doTestUrls(__file__)
|
||||
from ietf.utils.test_data import make_test_data
|
||||
|
||||
# class IndexTestCase(unittest.TestCase, RealDatabaseTest):
|
||||
# def setUp(self):
|
||||
# self.setUpRealDatabase()
|
||||
# def tearDown(self):
|
||||
# self.tearDownRealDatabase()
|
||||
from ietf.doc.models import *
|
||||
from ietf.idindex.index import *
|
||||
|
||||
# def testAllId(self):
|
||||
# print " Testing all_id.txt generation"
|
||||
# c = Client()
|
||||
# response = c.get('/drafts/_test/all_id.txt')
|
||||
# self.assertEquals(response.status_code, 200)
|
||||
# content = response.content
|
||||
# # Test that correct version number is shown for couple of old drafts
|
||||
# self.assert_(content.find("draft-ietf-tls-psk-09") >= 0)
|
||||
# self.assert_(content.find("draft-eronen-eap-sim-aka-80211-00") >= 0)
|
||||
# # Since all_id.txt contains all old drafts, it should never shrink
|
||||
# lines = content.split("\n")
|
||||
# self.assert_(len(lines) > 18000)
|
||||
# # Test that the lines look OK and have correct number of tabs
|
||||
# r = re.compile(r'^(draft-\S*-\d\d)\t(\d\d\d\d-\d\d-\d\d)\t([^\t]+)\t([^\t]*)$')
|
||||
# for line in lines:
|
||||
# if ((line == "") or
|
||||
# (line == "Internet-Drafts Status Summary") or
|
||||
# (line == "Web version is available at") or
|
||||
# (line == "https://datatracker.ietf.org/public/idindex.cgi")):
|
||||
# pass
|
||||
# elif r.match(line):
|
||||
# pass
|
||||
# else:
|
||||
# self.fail("Unexpected line \""+line+"\"")
|
||||
# print "OK (all_id.txt)"
|
||||
|
||||
class IndexTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
def setUp(self):
|
||||
self.id_dir = os.path.abspath("tmp-id-dir")
|
||||
os.mkdir(self.id_dir)
|
||||
settings.INTERNET_DRAFT_PATH = self.id_dir
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.id_dir)
|
||||
|
||||
def write_draft_file(self, name, size):
|
||||
with open(os.path.join(self.id_dir, name), 'w') as f:
|
||||
f.write("a" * size)
|
||||
|
||||
def test_all_id_txt(self):
|
||||
draft = make_test_data()
|
||||
|
||||
# active in IESG process
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="lc"))
|
||||
|
||||
txt = all_id_txt()
|
||||
|
||||
self.assertTrue(draft.name + "-" + draft.rev in txt)
|
||||
self.assertTrue(draft.get_state("draft-iesg").name in txt)
|
||||
|
||||
# not active in IESG process
|
||||
draft.unset_state("draft-iesg")
|
||||
|
||||
txt = all_id_txt()
|
||||
self.assertTrue(draft.name + "-" + draft.rev in txt)
|
||||
self.assertTrue("Active" in txt)
|
||||
|
||||
# published
|
||||
draft.set_state(State.objects.get(type="draft", slug="rfc"))
|
||||
DocAlias.objects.create(name="rfc1234", document=draft)
|
||||
|
||||
txt = all_id_txt()
|
||||
self.assertTrue(draft.name + "-" + draft.rev in txt)
|
||||
self.assertTrue("RFC\t1234" in txt)
|
||||
|
||||
# replaced
|
||||
draft.set_state(State.objects.get(type="draft", slug="repl"))
|
||||
|
||||
RelatedDocument.objects.create(
|
||||
relationship=DocRelationshipName.objects.get(slug="replaces"),
|
||||
source=Document.objects.create(type_id="draft", rev="00", name="draft-test-replacement"),
|
||||
target=draft.docalias_set.get(name__startswith="draft"))
|
||||
|
||||
txt = all_id_txt()
|
||||
self.assertTrue(draft.name + "-" + draft.rev in txt)
|
||||
self.assertTrue("Replaced replaced by draft-test-replacement" in txt)
|
||||
|
||||
def test_all_id2_txt(self):
|
||||
draft = make_test_data()
|
||||
|
||||
def get_fields(content):
|
||||
self.assertTrue(draft.name + "-" + draft.rev in content)
|
||||
|
||||
for line in content.splitlines():
|
||||
if line.startswith(draft.name + "-" + draft.rev):
|
||||
return line.split("\t")
|
||||
# test Active
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="review-e"))
|
||||
|
||||
NewRevisionDocEvent.objects.create(doc=draft, type="new_revision", rev=draft.rev, by=draft.ad)
|
||||
|
||||
self.write_draft_file("%s-%s.txt" % (draft.name, draft.rev), 5000)
|
||||
self.write_draft_file("%s-%s.pdf" % (draft.name, draft.rev), 5000)
|
||||
|
||||
t = get_fields(all_id2_txt())
|
||||
self.assertEqual(t[0], draft.name + "-" + draft.rev)
|
||||
self.assertEqual(t[1], "-1")
|
||||
self.assertEqual(t[2], "Active")
|
||||
self.assertEqual(t[3], "Expert Review")
|
||||
self.assertEqual(t[4], "")
|
||||
self.assertEqual(t[5], "")
|
||||
self.assertEqual(t[6], draft.latest_event(type="new_revision").time.strftime("%Y-%m-%d"))
|
||||
self.assertEqual(t[7], draft.group.acronym)
|
||||
self.assertEqual(t[8], draft.group.parent.acronym)
|
||||
self.assertEqual(t[9], unicode(draft.ad))
|
||||
self.assertEqual(t[10], draft.intended_std_level.name)
|
||||
self.assertEqual(t[11], "")
|
||||
self.assertEqual(t[12], ".pdf,.txt")
|
||||
self.assertEqual(t[13], draft.title)
|
||||
author = draft.documentauthor_set.order_by("order").get()
|
||||
self.assertEqual(t[14], "%s <%s>" % (author.author.person.name, author.author.address))
|
||||
self.assertEqual(t[15], "%s <%s>" % (draft.shepherd, draft.shepherd.email_address()))
|
||||
self.assertEqual(t[16], "%s <%s>" % (draft.ad, draft.ad.email_address()))
|
||||
|
||||
|
||||
# test RFC
|
||||
draft.set_state(State.objects.get(type="draft", slug="rfc"))
|
||||
DocAlias.objects.create(name="rfc1234", document=draft)
|
||||
t = get_fields(all_id2_txt())
|
||||
self.assertEqual(t[4], "1234")
|
||||
|
||||
# test Replaced
|
||||
draft.set_state(State.objects.get(type="draft", slug="repl"))
|
||||
RelatedDocument.objects.create(
|
||||
relationship=DocRelationshipName.objects.get(slug="replaces"),
|
||||
source=Document.objects.create(type_id="draft", rev="00", name="draft-test-replacement"),
|
||||
target=draft.docalias_set.get(name__startswith="draft"))
|
||||
|
||||
t = get_fields(all_id2_txt())
|
||||
self.assertEqual(t[5], "draft-test-replacement")
|
||||
|
||||
# test Last Call
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
draft.set_state(State.objects.get(type="draft-iesg", slug="lc"))
|
||||
|
||||
e = LastCallDocEvent.objects.create(doc=draft, type="sent_last_call", expires=datetime.datetime.now() + datetime.timedelta(days=14), by=draft.ad)
|
||||
|
||||
DocAlias.objects.create(name="rfc1234", document=draft)
|
||||
t = get_fields(all_id2_txt())
|
||||
self.assertEqual(t[11], e.expires.strftime("%Y-%m-%d"))
|
||||
|
||||
|
||||
def test_id_index_txt(self):
|
||||
draft = make_test_data()
|
||||
|
||||
draft.set_state(State.objects.get(type="draft", slug="active"))
|
||||
|
||||
txt = id_index_txt()
|
||||
|
||||
self.assertTrue(draft.name + "-" + draft.rev in txt)
|
||||
self.assertTrue(draft.title in txt)
|
||||
|
||||
self.assertTrue(draft.abstract[:20] not in txt)
|
||||
|
||||
txt = id_index_txt(with_abstracts=True)
|
||||
|
||||
self.assertTrue(draft.abstract[:20] in txt)
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
301 /drafts/wgid/1041/
|
||||
404 /drafts/wgid/987654/
|
||||
301 /drafts/wg/idr/
|
||||
301 /drafts/rfc/
|
||||
301 /drafts/current/
|
||||
301 /drafts/all/
|
||||
301 /drafts/dead/
|
||||
#301 /drafts/9574/related/
|
||||
#301 /drafts/9574/
|
||||
301 /drafts/draft-ietf-dnsext-dnssec-protocol/related/
|
||||
301 /drafts/draft-ietf-dnsext-dnssec-protocol/
|
||||
#404 /drafts/987654/
|
||||
301 /drafts/all_id_txt.html
|
||||
301 /drafts/all_id.html
|
||||
301 /drafts/
|
||||
#200,heavy /drafts/_test/all_id.txt
|
||||
# this takes 3 minutes, so disabled by default
|
||||
#200,heavy /drafts/_test/all_id2.txt
|
||||
#200,heavy /drafts/_test/id_index.txt
|
||||
#200,heavy /drafts/_test/id_abstracts.txt
|
|
@ -1,27 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls.defaults import patterns
|
||||
from ietf.idindex import views
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/'}),
|
||||
(r'^all/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/all/'}),
|
||||
(r'^rfc/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/all/#rfc'}),
|
||||
(r'^dead/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/all/#dead'}),
|
||||
(r'^current/$', 'django.views.generic.simple.redirect_to', { 'url': '/doc/active/'}),
|
||||
(r'^(?P<object_id>\d+)/(related/)?$', views.redirect_id),
|
||||
(r'^(?P<filename>[^/]+)/(related/)?$', views.redirect_filename),
|
||||
(r'^wgid/(?P<id>\d+)/$', views.wgdocs_redirect_id),
|
||||
(r'^wg/(?P<acronym>[^/]+)/$', views.wgdocs_redirect_acronym),
|
||||
(r'^all_id(?:_txt)?.html$', 'django.views.generic.simple.redirect_to', { 'url': 'http://www.ietf.org/id/all_id.txt' }),
|
||||
)
|
||||
|
||||
if settings.SERVER_MODE != 'production':
|
||||
# these haven't been ported
|
||||
urlpatterns += patterns('',
|
||||
(r'^_test/all_id.txt$', views.test_all_id_txt),
|
||||
(r'^_test/all_id2.txt$', views.test_all_id2_txt),
|
||||
(r'^_test/id_index.txt$', views.test_id_index_txt),
|
||||
(r'^_test/id_abstracts.txt$', views.test_id_abstracts_txt)
|
||||
)
|
|
@ -1,199 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
# Portions 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.
|
||||
|
||||
from django.http import HttpResponse, HttpResponsePermanentRedirect
|
||||
from django.template import loader
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.idtracker.models import Acronym, IETFWG, InternetDraft, IDInternal,PersonOrOrgInfo, Area
|
||||
from ietf.idtracker.templatetags.ietf_filters import clean_whitespace
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime as Datetime
|
||||
import pytz
|
||||
|
||||
def all_id_txt():
|
||||
# we need a distinct to prevent the queries below from multiplying the result
|
||||
all_ids = InternetDraft.objects.order_by('name').exclude(name__startswith="rfc").distinct()
|
||||
|
||||
inactive_states = ["pub", "watching", "dead"]
|
||||
|
||||
in_track_ids = all_ids.exclude(states__type="draft", states__slug="rfc").filter(states__type="draft-iesg").exclude(states__type="draft-iesg", states__slug__in=inactive_states)
|
||||
not_in_track = all_ids.filter(states__type="draft", states__slug="rfc") | all_ids.exclude(states__type="draft-iesg") | all_ids.filter(states__type="draft-iesg", states__slug__in=inactive_states)
|
||||
|
||||
active = not_in_track.filter(states__type="draft", states__slug="active")
|
||||
published = not_in_track.filter(states__type="draft", states__slug="rfc")
|
||||
expired = not_in_track.filter(states__type="draft", states__slug="expired")
|
||||
withdrawn_submitter = not_in_track.filter(states__type="draft", states__slug="auth-rm")
|
||||
withdrawn_ietf = not_in_track.filter(states__type="draft", states__slug="ietf-rm")
|
||||
replaced = not_in_track.filter(states__type="draft", states__slug="repl")
|
||||
|
||||
return loader.render_to_string("idindex/all_ids.txt",
|
||||
{ 'in_track_ids':in_track_ids,
|
||||
'active':active,
|
||||
'published':published,
|
||||
'expired':expired,
|
||||
'withdrawn_submitter':withdrawn_submitter,
|
||||
'withdrawn_ietf':withdrawn_ietf,
|
||||
'replaced':replaced})
|
||||
|
||||
def all_id2_entry(id):
|
||||
fields = []
|
||||
# 0
|
||||
fields.append(id.filename+"-"+id.revision_display())
|
||||
# 1
|
||||
fields.append(-1) # this used to be id.id_document_tag, we don't have this identifier anymore
|
||||
# 2
|
||||
status = str(id.get_state())
|
||||
fields.append(status)
|
||||
# 3
|
||||
iesgstate = id.idstate() if status=="Active" else ""
|
||||
fields.append(iesgstate)
|
||||
# 4
|
||||
fields.append(id.rfc_number if status=="RFC" else "")
|
||||
# 5
|
||||
try:
|
||||
fields.append(id.replaced_by.filename)
|
||||
except (AttributeError, InternetDraft.DoesNotExist):
|
||||
fields.append("")
|
||||
# 6
|
||||
fields.append(id.revision_date)
|
||||
# 7
|
||||
group_acronym = "" if id.group.type_id == "area" else id.group.acronym
|
||||
if group_acronym == "none":
|
||||
group_acronym = ""
|
||||
fields.append(group_acronym)
|
||||
# 8
|
||||
area = ""
|
||||
if id.group.type_id == "area":
|
||||
area = id.group.acronym
|
||||
elif id.group.type_id == "wg" and id.group.parent:
|
||||
area = id.group.parent.acronym
|
||||
fields.append(area)
|
||||
# 9 responsible AD name
|
||||
fields.append(id.idinternal.job_owner if id.idinternal else "")
|
||||
# 10
|
||||
s = id.intended_status
|
||||
if s and str(s) not in ("None","Request"):
|
||||
fields.append(str(s))
|
||||
else:
|
||||
fields.append("")
|
||||
# 11
|
||||
if (iesgstate=="In Last Call") or iesgstate.startswith("In Last Call::"):
|
||||
fields.append(id.lc_expiration_date)
|
||||
else:
|
||||
fields.append("")
|
||||
# 12
|
||||
fields.append(id.file_type if status=="Active" else "")
|
||||
# 13
|
||||
fields.append(clean_whitespace(id.title))
|
||||
# 14
|
||||
authors = []
|
||||
for author in sorted(id.authors.all(), key=lambda x: x.final_author_order()):
|
||||
try:
|
||||
realname = unicode(author.person)
|
||||
email = author.email() or ""
|
||||
name = re.sub(u"[<>@,]", u"", realname) + u" <"+re.sub(u"[<>,]", u"", email).strip()+u">"
|
||||
authors.append(clean_whitespace(name))
|
||||
except PersonOrOrgInfo.DoesNotExist:
|
||||
pass
|
||||
fields.append(u", ".join(authors))
|
||||
# 15
|
||||
if id.shepherd:
|
||||
shepherd = id.shepherd
|
||||
realname = unicode(shepherd)
|
||||
email = shepherd.email_address()
|
||||
name = re.sub(u"[<>@,]", u"", realname) + u" <"+re.sub(u"[<>,]", u"", email).strip()+u">"
|
||||
else:
|
||||
name = u""
|
||||
fields.append(name)
|
||||
# 16 Responsible AD name and email
|
||||
if id.ad:
|
||||
ad = id.ad
|
||||
realname = unicode(ad)
|
||||
email = ad.email_address()
|
||||
name = re.sub(u"[<>@,]", u"", realname) + u" <"+re.sub(u"[<>,]", u"", email).strip()+u">"
|
||||
else:
|
||||
name = u""
|
||||
fields.append(name)
|
||||
#
|
||||
return "\t".join([unicode(x) for x in fields])
|
||||
|
||||
def all_id2_txt():
|
||||
all_ids = InternetDraft.objects.order_by('name').exclude(name__startswith="rfc").select_related('group', 'group__parent', 'ad')
|
||||
data = "\n".join(all_id2_entry(id) for id in all_ids)
|
||||
|
||||
return loader.render_to_string("idindex/all_id2.txt",{'data':data})
|
||||
|
||||
def id_index_txt():
|
||||
groups = IETFWG.objects.all()
|
||||
return loader.render_to_string("idindex/id_index.txt", {'groups':groups})
|
||||
|
||||
def id_abstracts_txt():
|
||||
groups = IETFWG.objects.all()
|
||||
return loader.render_to_string("idindex/id_abstracts.txt", {'groups':groups, 'time':Datetime.now(pytz.UTC).strftime("%Y-%m-%d %H:%M:%S %Z")})
|
||||
|
||||
def test_all_id_txt(request):
|
||||
return HttpResponse(all_id_txt(), mimetype='text/plain')
|
||||
def test_all_id2_txt(request):
|
||||
return HttpResponse(all_id2_txt(), mimetype='text/plain')
|
||||
def test_id_index_txt(request):
|
||||
return HttpResponse(id_index_txt(), mimetype='text/plain')
|
||||
def test_id_abstracts_txt(request):
|
||||
return HttpResponse(id_abstracts_txt(), mimetype='text/plain')
|
||||
|
||||
def redirect_id(request, object_id):
|
||||
'''Redirect from historical document ID to preferred filename url.'''
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
return HttpResponsePermanentRedirect("/doc/")
|
||||
|
||||
doc = get_object_or_404(InternetDraft, id_document_tag=object_id)
|
||||
return HttpResponsePermanentRedirect("/doc/"+doc.filename+"/")
|
||||
|
||||
def redirect_filename(request, filename):
|
||||
return HttpResponsePermanentRedirect("/doc/"+filename+"/")
|
||||
|
||||
def wgdocs_redirect_id(request, id):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.group.models import Group
|
||||
group = get_object_or_404(Group, id=id)
|
||||
return HttpResponsePermanentRedirect("/wg/%s/" % group.acronym)
|
||||
|
||||
group = get_object_or_404(Acronym, acronym_id=id)
|
||||
return HttpResponsePermanentRedirect("/wg/"+group.acronym+"/")
|
||||
|
||||
def wgdocs_redirect_acronym(request, acronym):
|
||||
return HttpResponsePermanentRedirect("/wg/"+acronym+"/")
|
||||
|
|
@ -6,105 +6,64 @@ from django.db.models import Q
|
|||
|
||||
import datetime, os, shutil, glob, re, itertools
|
||||
|
||||
from ietf.idtracker.models import InternetDraft, IDDates, IDStatus, IDState, DocumentComment, IDAuthor, WGChair
|
||||
from ietf.utils.mail import send_mail, send_mail_subj
|
||||
from ietf.idrfc.utils import log_state_changed, add_document_comment
|
||||
from ietf.doc.models import Document, DocEvent, save_document_in_history, State
|
||||
from ietf.name.models import DocTagName
|
||||
from ietf.idrfc.utils import log_state_changed
|
||||
from ietf.doc.models import Document, DocEvent, State, save_document_in_history, IESG_SUBSTATE_TAGS
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.meeting.models import Meeting
|
||||
|
||||
def in_id_expire_freeze(when=None):
|
||||
if when == None:
|
||||
when = datetime.datetime.now()
|
||||
def expirable_draft(draft):
|
||||
"""Return whether draft is in an expirable state or not. This is
|
||||
the single draft version of the logic in expirable_drafts. These
|
||||
two functions need to be kept in sync."""
|
||||
return (draft.expires and draft.get_state_slug() == "active"
|
||||
and draft.get_state_slug("draft-iesg") in (None, "watching", "dead")
|
||||
and draft.get_state_slug("draft-stream-%s" % draft.stream_id) not in ("rfc-edit", "pub")
|
||||
and not draft.tags.filter(slug="rfc-rev"))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
d = Meeting.get_second_cut_off()
|
||||
else:
|
||||
d = IDDates.objects.get(id=IDDates.SECOND_CUT_OFF).date
|
||||
# for some reason, the old Perl code started at 9 am
|
||||
second_cut_off = datetime.datetime.combine(d, datetime.time(9, 0))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
d = Meeting.get_ietf_monday()
|
||||
else:
|
||||
d = IDDates.objects.get(id=IDDates.IETF_MONDAY).date
|
||||
ietf_monday = datetime.datetime.combine(d, datetime.time(0, 0))
|
||||
|
||||
return second_cut_off <= when < ietf_monday
|
||||
|
||||
def expirable_documents():
|
||||
def expirable_drafts():
|
||||
"""Return a queryset with expirable drafts."""
|
||||
# the general rule is that each active draft is expirable, unless
|
||||
# it's in a state where we shouldn't touch it
|
||||
|
||||
d = Document.objects.filter(states__type="draft", states__slug="active").exclude(tags="rfc-rev")
|
||||
d = Document.objects.filter(states__type="draft", states__slug="active").exclude(expires=None)
|
||||
|
||||
nonexpirable_states = []
|
||||
# all IESG states except AD Watching and Dead block expiry
|
||||
nonexpirable_states += list(State.objects.filter(used=True, type="draft-iesg").exclude(slug__in=("watching", "dead")))
|
||||
# Sent to RFC Editor and RFC Published block expiry (the latter
|
||||
# sent to RFC Editor and RFC Published block expiry (the latter
|
||||
# shouldn't be possible for an active draft, though)
|
||||
nonexpirable_states += list(State.objects.filter(used=True, type__in=("draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"), slug__in=("rfc-edit", "pub")))
|
||||
|
||||
return d.exclude(states__in=nonexpirable_states).distinct()
|
||||
d = d.exclude(states__in=nonexpirable_states)
|
||||
|
||||
def get_soon_to_expire_ids(days):
|
||||
start_date = datetime.date.today() - datetime.timedelta(InternetDraft.DAYS_TO_EXPIRE - 1)
|
||||
end_date = start_date + datetime.timedelta(days - 1)
|
||||
|
||||
for d in InternetDraft.objects.filter(revision_date__gte=start_date,revision_date__lte=end_date,status__status='Active'):
|
||||
if d.can_expire():
|
||||
yield d
|
||||
# under review by the RFC Editor blocks expiry
|
||||
d = d.exclude(tags="rfc-rev")
|
||||
|
||||
def get_soon_to_expire_idsREDESIGN(days):
|
||||
return d.distinct()
|
||||
|
||||
def get_soon_to_expire_drafts(days_of_warning):
|
||||
start_date = datetime.date.today() - datetime.timedelta(1)
|
||||
end_date = start_date + datetime.timedelta(days - 1)
|
||||
end_date = start_date + datetime.timedelta(days_of_warning)
|
||||
|
||||
return expirable_drafts().filter(expires__gte=start_date, expires__lt=end_date)
|
||||
|
||||
def get_expired_drafts():
|
||||
return expirable_drafts().filter(expires__lt=datetime.date.today() + datetime.timedelta(1))
|
||||
|
||||
def in_draft_expire_freeze(when=None):
|
||||
if when == None:
|
||||
when = datetime.datetime.now()
|
||||
|
||||
d = Meeting.get_second_cut_off()
|
||||
# for some reason, the old Perl code started at 9 am
|
||||
second_cut_off = datetime.datetime.combine(d, datetime.time(9, 0))
|
||||
|
||||
for d in expirable_documents():
|
||||
if d.expires and start_date <= d.expires.date() <= end_date:
|
||||
yield d
|
||||
|
||||
def get_expired_ids():
|
||||
cut_off = datetime.date.today() - datetime.timedelta(days=InternetDraft.DAYS_TO_EXPIRE)
|
||||
|
||||
return InternetDraft.objects.filter(
|
||||
revision_date__lte=cut_off,
|
||||
status__status="Active",
|
||||
review_by_rfc_editor=0).filter(
|
||||
Q(idinternal=None) | Q(idinternal__cur_state__document_state_id__gte=42))
|
||||
|
||||
def get_expired_idsREDESIGN():
|
||||
today = datetime.date.today()
|
||||
|
||||
for d in expirable_documents():
|
||||
if d.expires and d.expires.date() <= today:
|
||||
yield d
|
||||
|
||||
def send_expire_warning_for_id(doc):
|
||||
expiration = doc.expiration()
|
||||
# Todo:
|
||||
#second_cutoff = IDDates.objects.get(date_id=2)
|
||||
#ietf_monday = IDDates.objects.get(date_id=3)
|
||||
#freeze_delta = ietf_monday - second_cutoff
|
||||
# # The I-D expiration job doesn't run while submissions are frozen.
|
||||
# if ietf_monday > expiration > second_cutoff:
|
||||
# expiration += freeze_delta
|
||||
d = Meeting.get_ietf_monday()
|
||||
ietf_monday = datetime.datetime.combine(d, datetime.time(0, 0))
|
||||
|
||||
authors = doc.authors.all()
|
||||
to_addrs = [author.email() for author in authors if author.email()]
|
||||
cc_addrs = None
|
||||
if doc.group.acronym != 'none':
|
||||
cc_addrs = [chair.person.email() for chair in WGChair.objects.filter(group_acronym=doc.group)]
|
||||
return second_cut_off <= when < ietf_monday
|
||||
|
||||
if to_addrs or cc_addrs:
|
||||
send_mail_subj(None, to_addrs, None, 'notify_expirations/subject.txt', 'notify_expirations/body.txt',
|
||||
{
|
||||
'draft':doc,
|
||||
'expiration':expiration,
|
||||
},
|
||||
cc_addrs)
|
||||
|
||||
def send_expire_warning_for_idREDESIGN(doc):
|
||||
def send_expire_warning_for_draft(doc):
|
||||
if doc.get_state_slug("draft-iesg") == "dead":
|
||||
return # don't warn about dead documents
|
||||
|
||||
|
@ -130,23 +89,7 @@ def send_expire_warning_for_idREDESIGN(doc):
|
|||
),
|
||||
cc=cc)
|
||||
|
||||
def send_expire_notice_for_id(doc):
|
||||
doc.dunn_sent_date = datetime.date.today()
|
||||
doc.save()
|
||||
|
||||
if not doc.idinternal:
|
||||
return
|
||||
|
||||
request = None
|
||||
to = u"%s <%s>" % doc.idinternal.job_owner.person.email()
|
||||
send_mail(request, to,
|
||||
"I-D Expiring System <ietf-secretariat-reply@ietf.org>",
|
||||
u"I-D was expired %s" % doc.file_tag(),
|
||||
"idrfc/id_expired_email.txt",
|
||||
dict(doc=doc,
|
||||
state=doc.idstate()))
|
||||
|
||||
def send_expire_notice_for_idREDESIGN(doc):
|
||||
def send_expire_notice_for_draft(doc):
|
||||
if not doc.ad or doc.get_state_slug("draft-iesg") == "dead":
|
||||
return
|
||||
|
||||
|
@ -163,42 +106,6 @@ def send_expire_notice_for_idREDESIGN(doc):
|
|||
state=state,
|
||||
))
|
||||
|
||||
def expire_id(doc):
|
||||
def move_file(f):
|
||||
src = os.path.join(settings.INTERNET_DRAFT_PATH, f)
|
||||
dst = os.path.join(settings.INTERNET_DRAFT_ARCHIVE_DIR, f)
|
||||
|
||||
if os.path.exists(src):
|
||||
shutil.move(src, dst)
|
||||
|
||||
move_file("%s-%s.txt" % (doc.filename, doc.revision_display()))
|
||||
move_file("%s-%s.txt.p7s" % (doc.filename, doc.revision_display()))
|
||||
move_file("%s-%s.ps" % (doc.filename, doc.revision_display()))
|
||||
move_file("%s-%s.pdf" % (doc.filename, doc.revision_display()))
|
||||
|
||||
new_revision = "%02d" % (int(doc.revision) + 1)
|
||||
|
||||
new_file = open(os.path.join(settings.INTERNET_DRAFT_PATH, "%s-%s.txt" % (doc.filename, new_revision)), 'w')
|
||||
txt = render_to_string("idrfc/expire_text.txt",
|
||||
dict(doc=doc,
|
||||
authors=[a.person.email() for a in doc.authors.all()],
|
||||
expire_days=InternetDraft.DAYS_TO_EXPIRE))
|
||||
new_file.write(txt)
|
||||
new_file.close()
|
||||
|
||||
doc.revision = new_revision
|
||||
doc.expiration_date = datetime.date.today()
|
||||
doc.last_modified_date = datetime.date.today()
|
||||
doc.status = IDStatus.objects.get(status="Expired")
|
||||
doc.save()
|
||||
|
||||
if doc.idinternal:
|
||||
if doc.idinternal.cur_state_id != IDState.DEAD:
|
||||
doc.idinternal.change_state(IDState.objects.get(document_state_id=IDState.DEAD), None)
|
||||
log_state_changed(None, doc, "system")
|
||||
|
||||
add_document_comment(None, doc, "Document is expired by system")
|
||||
|
||||
def move_draft_files_to_archive(doc, rev):
|
||||
def move_file(f):
|
||||
src = os.path.join(settings.INTERNET_DRAFT_PATH, f)
|
||||
|
@ -211,7 +118,7 @@ def move_draft_files_to_archive(doc, rev):
|
|||
for t in file_types:
|
||||
move_file("%s-%s.%s" % (doc.name, rev, t))
|
||||
|
||||
def expire_idREDESIGN(doc):
|
||||
def expire_draft(doc):
|
||||
# clean up files
|
||||
move_draft_files_to_archive(doc, doc.rev)
|
||||
|
||||
|
@ -222,7 +129,7 @@ def expire_idREDESIGN(doc):
|
|||
if doc.latest_event(type='started_iesg_process'):
|
||||
dead_state = State.objects.get(used=True, type="draft-iesg", slug="dead")
|
||||
prev = doc.get_state("draft-iesg")
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev != dead_state:
|
||||
doc.set_state(dead_state)
|
||||
|
@ -239,67 +146,7 @@ def expire_idREDESIGN(doc):
|
|||
doc.time = datetime.datetime.now()
|
||||
doc.save()
|
||||
|
||||
def clean_up_id_files():
|
||||
"""Move unidentified and old files out of the Internet Draft directory."""
|
||||
cut_off = datetime.date.today() - datetime.timedelta(days=InternetDraft.DAYS_TO_EXPIRE)
|
||||
|
||||
pattern = os.path.join(settings.INTERNET_DRAFT_PATH, "draft-*.*")
|
||||
files = []
|
||||
filename_re = re.compile('^(.*)-(\d\d)$')
|
||||
|
||||
def splitext(fn):
|
||||
"""
|
||||
Split the pathname path into a pair (root, ext) such that root + ext
|
||||
== path, and ext is empty or begins with a period and contains all
|
||||
periods in the last path component.
|
||||
|
||||
This differs from os.path.splitext in the number of periods in the ext
|
||||
parts when the final path component containt more than one period.
|
||||
"""
|
||||
s = fn.rfind("/")
|
||||
if s == -1:
|
||||
s = 0
|
||||
i = fn[s:].find(".")
|
||||
if i == -1:
|
||||
return fn, ''
|
||||
else:
|
||||
return fn[:s+i], fn[s+i:]
|
||||
|
||||
for path in glob.glob(pattern):
|
||||
basename = os.path.basename(path)
|
||||
stem, ext = splitext(basename)
|
||||
match = filename_re.search(stem)
|
||||
if not match:
|
||||
filename, revision = ("UNKNOWN", "00")
|
||||
else:
|
||||
filename, revision = match.groups()
|
||||
|
||||
def move_file_to(subdir):
|
||||
shutil.move(path,
|
||||
os.path.join(settings.INTERNET_DRAFT_ARCHIVE_DIR, subdir, basename))
|
||||
|
||||
try:
|
||||
doc = InternetDraft.objects.get(filename=filename, revision=revision)
|
||||
|
||||
if doc.status_id == 3: # RFC
|
||||
if ext != ".txt":
|
||||
move_file_to("unknown_ids")
|
||||
elif doc.status_id in (2, 4, 5, 6) and doc.expiration_date and doc.expiration_date < cut_off:
|
||||
# Expired, Withdrawn by Auth, Replaced, Withdrawn by IETF,
|
||||
# and expired more than DAYS_TO_EXPIRE ago
|
||||
if os.path.getsize(path) < 1500:
|
||||
move_file_to("deleted_tombstones")
|
||||
# revert version after having deleted tombstone
|
||||
doc.revision = "%02d" % (int(revision) - 1)
|
||||
doc.expired_tombstone = True
|
||||
doc.save()
|
||||
else:
|
||||
move_file_to("expired_without_tombstone")
|
||||
|
||||
except InternetDraft.DoesNotExist:
|
||||
move_file_to("unknown_ids")
|
||||
|
||||
def clean_up_id_filesREDESIGN():
|
||||
def clean_up_draft_files():
|
||||
"""Move unidentified and old files out of the Internet Draft directory."""
|
||||
cut_off = datetime.date.today()
|
||||
|
||||
|
@ -314,7 +161,7 @@ def clean_up_id_filesREDESIGN():
|
|||
periods in the last path component.
|
||||
|
||||
This differs from os.path.splitext in the number of periods in the ext
|
||||
parts when the final path component containt more than one period.
|
||||
parts when the final path component contains more than one period.
|
||||
"""
|
||||
s = fn.rfind("/")
|
||||
if s == -1:
|
||||
|
@ -357,11 +204,3 @@ def clean_up_id_filesREDESIGN():
|
|||
|
||||
except Document.DoesNotExist:
|
||||
move_file_to("unknown_ids")
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
get_soon_to_expire_ids = get_soon_to_expire_idsREDESIGN
|
||||
get_expired_ids = get_expired_idsREDESIGN
|
||||
send_expire_warning_for_id = send_expire_warning_for_idREDESIGN
|
||||
send_expire_notice_for_id = send_expire_notice_for_idREDESIGN
|
||||
expire_id = expire_idREDESIGN
|
||||
clean_up_id_files = clean_up_id_filesREDESIGN
|
||||
|
|
|
@ -8,7 +8,7 @@ from ietf.idtracker.models import InternetDraft, DocumentComment, BallotInfo
|
|||
from ietf.idrfc.mails import *
|
||||
from ietf.idrfc.utils import *
|
||||
|
||||
from ietf.doc.models import Document, DocEvent, LastCallDocEvent, WriteupDocEvent, save_document_in_history, State
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import Person
|
||||
|
||||
def request_last_call(request, doc):
|
||||
|
@ -83,7 +83,7 @@ def expire_last_callREDESIGN(doc):
|
|||
prev = doc.get_state("draft-iesg")
|
||||
doc.set_state(state)
|
||||
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
|
|
@ -30,42 +30,31 @@
|
|||
# (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 datetime
|
||||
|
||||
from django import template
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from ietf.idtracker.models import IDInternal, BallotInfo
|
||||
from ietf.idrfc.idrfc_wrapper import position_to_string, BALLOT_ACTIVE_STATES
|
||||
from ietf.idtracker.templatetags.ietf_filters import in_group, timesince_days
|
||||
from ietf.ietfauth.decorators import has_role
|
||||
from ietf.doc.models import BallotDocEvent, BallotPositionDocEvent
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from datetime import date
|
||||
from ietf.ietfauth.utils import user_is_person, has_role
|
||||
from ietf.doc.models import BallotDocEvent, BallotPositionDocEvent, IESG_BALLOT_ACTIVE_STATES, IESG_SUBSTATE_TAGS
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def get_user_name(context):
|
||||
if 'user' in context and context['user'].is_authenticated():
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.person.models import Person
|
||||
try:
|
||||
return context['user'].get_profile().plain_name()
|
||||
except Person.DoesNotExist:
|
||||
return None
|
||||
|
||||
person = context['user'].get_profile().person()
|
||||
if person:
|
||||
return str(person)
|
||||
return None
|
||||
|
||||
def render_ballot_icon(user, doc):
|
||||
if not doc:
|
||||
return ""
|
||||
|
||||
# FIXME: temporary backwards-compatibility hack
|
||||
from ietf.doc.models import Document
|
||||
if not isinstance(doc, Document):
|
||||
doc = doc._draft
|
||||
|
||||
if doc.type_id == "draft":
|
||||
s = doc.get_state("draft-iesg")
|
||||
if s and s.name not in BALLOT_ACTIVE_STATES:
|
||||
if doc.get_state_slug("draft-iesg") not in IESG_BALLOT_ACTIVE_STATES:
|
||||
return ""
|
||||
elif doc.type_id == "charter":
|
||||
if doc.get_state_slug() not in ("intrev", "iesgrev"):
|
||||
|
@ -77,12 +66,10 @@ def render_ballot_icon(user, doc):
|
|||
if doc.get_state_slug() not in ("iesgeval","defer"):
|
||||
return ""
|
||||
|
||||
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
|
||||
ballot = doc.active_ballot()
|
||||
if not ballot:
|
||||
return ""
|
||||
|
||||
edit_position_url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
|
||||
|
||||
def sort_key(t):
|
||||
_, pos = t
|
||||
if not pos:
|
||||
|
@ -95,11 +82,18 @@ def render_ballot_icon(user, doc):
|
|||
positions = list(doc.active_ballot().active_ad_positions().items())
|
||||
positions.sort(key=sort_key)
|
||||
|
||||
cm = ""
|
||||
edit_position_url = ""
|
||||
if has_role(user, "Area Director"):
|
||||
cm = ' oncontextmenu="editBallot(\''+str(edit_position_url)+'\');return false;"'
|
||||
edit_position_url = urlreverse('ietf.idrfc.views_ballot.edit_position', kwargs=dict(name=doc.name, ballot_id=ballot.pk))
|
||||
|
||||
res = ['<table class="ballot_icon" title="IESG Evaluation Record (click to show more, right-click to edit position)" onclick="showBallot(\'' + doc.name + '\',\'' + str(edit_position_url) + '\')"' + cm + '>']
|
||||
title = "IESG positions (click to show more%s)" % (", right-click to edit position" if edit_position_url else "")
|
||||
|
||||
res = ['<a href="%s" data-popup="%s" data-edit="%s" title="%s" class="ballot-icon"><table>' % (
|
||||
urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
|
||||
urlreverse("ietf.doc.views_doc.ballot_popup", kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
|
||||
edit_position_url,
|
||||
title
|
||||
)]
|
||||
|
||||
res.append("<tr>")
|
||||
|
||||
|
@ -110,13 +104,13 @@ def render_ballot_icon(user, doc):
|
|||
|
||||
c = "position-%s" % (pos.pos.slug if pos else "norecord")
|
||||
|
||||
if hasattr(user, "get_profile") and ad == user.get_profile():
|
||||
if user_is_person(user, ad):
|
||||
c += " my"
|
||||
|
||||
res.append('<td class="%s" />' % c)
|
||||
|
||||
res.append("</tr>")
|
||||
res.append("</table>")
|
||||
res.append("</table></a>")
|
||||
|
||||
return "".join(res)
|
||||
|
||||
|
@ -125,48 +119,51 @@ class BallotIconNode(template.Node):
|
|||
self.doc_var = doc_var
|
||||
def render(self, context):
|
||||
doc = template.resolve_variable(self.doc_var, context)
|
||||
#if hasattr(doc, "_idinternal"):
|
||||
# # hack for old schema
|
||||
# doc = doc._idinternal
|
||||
return render_ballot_icon(context.get("user"), doc)
|
||||
|
||||
def do_ballot_icon(parser, token):
|
||||
try:
|
||||
tagName, docName = token.split_contents()
|
||||
tag_name, doc_name = token.split_contents()
|
||||
except ValueError:
|
||||
raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
|
||||
return BallotIconNode(docName)
|
||||
return BallotIconNode(doc_name)
|
||||
|
||||
register.tag('ballot_icon', do_ballot_icon)
|
||||
|
||||
|
||||
@register.filter
|
||||
def my_position(doc, user):
|
||||
user_name = get_user_name({'user':user})
|
||||
if not user_name:
|
||||
return None
|
||||
if not in_group(user, "Area_Director"):
|
||||
if not has_role(user, "Area Director"):
|
||||
return None
|
||||
# FIXME: temporary backwards-compatibility hack
|
||||
from ietf.doc.models import Document
|
||||
if not isinstance(doc, Document):
|
||||
doc = doc._draft
|
||||
|
||||
ballot = doc.active_ballot()
|
||||
pos = "No Record"
|
||||
if ballot:
|
||||
changed_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad__name=user_name, ballot=ballot)
|
||||
if changed_pos:
|
||||
pos = changed_pos.pos.name;
|
||||
changed_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad__user=user, ballot=ballot)
|
||||
if changed_pos:
|
||||
pos = changed_pos.pos.name;
|
||||
return pos
|
||||
|
||||
@register.filter
|
||||
@register.filter()
|
||||
def state_age_colored(doc):
|
||||
if doc.type.slug == 'draft':
|
||||
if not doc.latest_event(type='started_iesg_process'):
|
||||
return ""
|
||||
# FIXME: temporary backwards-compatibility hack
|
||||
from ietf.doc.models import Document
|
||||
if not isinstance(doc, Document):
|
||||
doc = doc._draft
|
||||
|
||||
if doc.type_id == 'draft':
|
||||
if not doc.get_state_slug() in ["active", "rfc"]:
|
||||
# Don't show anything for expired/withdrawn/replaced drafts
|
||||
return ""
|
||||
main_state = doc.get_state('draft-iesg')
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
sub_states = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
main_state = doc.get_state_slug('draft-iesg')
|
||||
if not main_state:
|
||||
return ""
|
||||
|
||||
if main_state.slug in ["dead","watching","pub"]:
|
||||
if main_state in ["dead", "watching", "pub"]:
|
||||
return ""
|
||||
try:
|
||||
state_date = doc.docevent_set.filter(
|
||||
|
@ -181,26 +178,26 @@ def state_age_colored(doc):
|
|||
Q(desc__istartswith="IESG process started in state")
|
||||
).order_by('-time')[0].time.date()
|
||||
except IndexError:
|
||||
state_date = date(1990,1,1)
|
||||
days = timesince_days(state_date)
|
||||
state_date = datetime.date(1990,1,1)
|
||||
days = (datetime.date.today() - state_date).days
|
||||
# loosely based on
|
||||
# http://trac.tools.ietf.org/group/iesg/trac/wiki/PublishPath
|
||||
if main_state.slug == "lc":
|
||||
if main_state == "lc":
|
||||
goal1 = 30
|
||||
goal2 = 30
|
||||
elif main_state.slug == "rfcqueue":
|
||||
elif main_state == "rfcqueue":
|
||||
goal1 = 60
|
||||
goal2 = 120
|
||||
elif main_state.slug in ["lc-req", "ann"]:
|
||||
elif main_state in ["lc-req", "ann"]:
|
||||
goal1 = 4
|
||||
goal2 = 7
|
||||
elif 'need-rev' in [x.slug for x in sub_states]:
|
||||
elif 'need-rev' in [x.slug for x in doc.tags.all()]:
|
||||
goal1 = 14
|
||||
goal2 = 28
|
||||
elif main_state.slug == "pub-req":
|
||||
elif main_state == "pub-req":
|
||||
goal1 = 7
|
||||
goal2 = 14
|
||||
elif main_state.slug == "ad-eval":
|
||||
elif main_state == "ad-eval":
|
||||
goal1 = 14
|
||||
goal2 = 28
|
||||
else:
|
||||
|
@ -216,6 +213,7 @@ def state_age_colored(doc):
|
|||
title = ' title="Goal is <%d days"' % (goal1,)
|
||||
else:
|
||||
title = ''
|
||||
return '<span class="%s"%s>(for %d day%s)</span>' % (class_name,title,days,('','s')[days != 1])
|
||||
return mark_safe('<span class="%s"%s>(for %d day%s)</span>' % (
|
||||
class_name, title, days, 's' if days != 1 else ''))
|
||||
else:
|
||||
return ""
|
||||
|
|
|
@ -1013,13 +1013,13 @@ class ExpireIDsTestCase(django.test.TestCase):
|
|||
shutil.rmtree(self.id_dir)
|
||||
shutil.rmtree(self.archive_dir)
|
||||
|
||||
def write_id_file(self, name, size):
|
||||
def write_draft_file(self, name, size):
|
||||
f = open(os.path.join(self.id_dir, name), 'w')
|
||||
f.write("a" * size)
|
||||
f.close()
|
||||
|
||||
def test_in_id_expire_freeze(self):
|
||||
from ietf.idrfc.expire import in_id_expire_freeze
|
||||
def test_in_draft_expire_freeze(self):
|
||||
from ietf.idrfc.expire import in_draft_expire_freeze
|
||||
|
||||
Meeting.objects.create(number="123",
|
||||
type=MeetingTypeName.objects.get(slug="ietf"),
|
||||
|
@ -1027,70 +1027,70 @@ class ExpireIDsTestCase(django.test.TestCase):
|
|||
second_cut_off = Meeting.get_second_cut_off()
|
||||
ietf_monday = Meeting.get_ietf_monday()
|
||||
|
||||
self.assertTrue(not in_id_expire_freeze(datetime.datetime.combine(second_cut_off - datetime.timedelta(days=7), time(0, 0, 0))))
|
||||
self.assertTrue(not in_id_expire_freeze(datetime.datetime.combine(second_cut_off, time(0, 0, 0))))
|
||||
self.assertTrue(in_id_expire_freeze(datetime.datetime.combine(second_cut_off + datetime.timedelta(days=7), time(0, 0, 0))))
|
||||
self.assertTrue(in_id_expire_freeze(datetime.datetime.combine(ietf_monday - datetime.timedelta(days=1), time(0, 0, 0))))
|
||||
self.assertTrue(not in_id_expire_freeze(datetime.datetime.combine(ietf_monday, time(0, 0, 0))))
|
||||
self.assertTrue(not in_draft_expire_freeze(datetime.datetime.combine(second_cut_off - datetime.timedelta(days=7), time(0, 0, 0))))
|
||||
self.assertTrue(not in_draft_expire_freeze(datetime.datetime.combine(second_cut_off, time(0, 0, 0))))
|
||||
self.assertTrue(in_draft_expire_freeze(datetime.datetime.combine(second_cut_off + datetime.timedelta(days=7), time(0, 0, 0))))
|
||||
self.assertTrue(in_draft_expire_freeze(datetime.datetime.combine(ietf_monday - datetime.timedelta(days=1), time(0, 0, 0))))
|
||||
self.assertTrue(not in_draft_expire_freeze(datetime.datetime.combine(ietf_monday, time(0, 0, 0))))
|
||||
|
||||
def test_warn_expirable_ids(self):
|
||||
from ietf.idrfc.expire import get_soon_to_expire_ids, send_expire_warning_for_id
|
||||
def test_warn_expirable_drafts(self):
|
||||
from ietf.idrfc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft
|
||||
|
||||
draft = make_test_data()
|
||||
|
||||
self.assertEquals(len(list(get_soon_to_expire_ids(14))), 0)
|
||||
self.assertEquals(len(list(get_soon_to_expire_drafts(14))), 0)
|
||||
|
||||
# hack into expirable state
|
||||
draft.unset_state("draft-iesg")
|
||||
draft.expires = datetime.datetime.now() + datetime.timedelta(days=10)
|
||||
draft.save()
|
||||
|
||||
self.assertEquals(len(list(get_soon_to_expire_ids(14))), 1)
|
||||
self.assertEquals(len(list(get_soon_to_expire_drafts(14))), 1)
|
||||
|
||||
# test send warning
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
send_expire_warning_for_id(draft)
|
||||
send_expire_warning_for_draft(draft)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("aread@ietf.org" in str(outbox[-1])) # author
|
||||
self.assertTrue("wgchairman@ietf.org" in str(outbox[-1]))
|
||||
|
||||
def test_expire_ids(self):
|
||||
from ietf.idrfc.expire import get_expired_ids, send_expire_notice_for_id, expire_id
|
||||
def test_expire_drafts(self):
|
||||
from ietf.idrfc.expire import get_expired_drafts, send_expire_notice_for_draft, expire_draft
|
||||
|
||||
draft = make_test_data()
|
||||
|
||||
self.assertEquals(len(list(get_expired_ids())), 0)
|
||||
self.assertEquals(len(list(get_expired_drafts())), 0)
|
||||
|
||||
# hack into expirable state
|
||||
draft.unset_state("draft-iesg")
|
||||
draft.expires = datetime.datetime.now()
|
||||
draft.save()
|
||||
|
||||
self.assertEquals(len(list(get_expired_ids())), 1)
|
||||
self.assertEquals(len(list(get_expired_drafts())), 1)
|
||||
|
||||
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="watching"))
|
||||
|
||||
self.assertEquals(len(list(get_expired_ids())), 1)
|
||||
self.assertEquals(len(list(get_expired_drafts())), 1)
|
||||
|
||||
draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="iesg-eva"))
|
||||
|
||||
self.assertEquals(len(list(get_expired_ids())), 0)
|
||||
self.assertEquals(len(list(get_expired_drafts())), 0)
|
||||
|
||||
# test notice
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
send_expire_notice_for_id(draft)
|
||||
send_expire_notice_for_draft(draft)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("expired" in outbox[-1]["Subject"])
|
||||
|
||||
# test expiry
|
||||
txt = "%s-%s.txt" % (draft.name, draft.rev)
|
||||
self.write_id_file(txt, 5000)
|
||||
self.write_draft_file(txt, 5000)
|
||||
|
||||
expire_id(draft)
|
||||
expire_draft(draft)
|
||||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEquals(draft.get_state_slug(), "expired")
|
||||
|
@ -1099,16 +1099,16 @@ class ExpireIDsTestCase(django.test.TestCase):
|
|||
self.assertTrue(not os.path.exists(os.path.join(self.id_dir, txt)))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.archive_dir, txt)))
|
||||
|
||||
def test_clean_up_id_files(self):
|
||||
def test_clean_up_draft_files(self):
|
||||
draft = make_test_data()
|
||||
|
||||
from ietf.idrfc.expire import clean_up_id_files
|
||||
from ietf.idrfc.expire import clean_up_draft_files
|
||||
|
||||
# put unknown file
|
||||
unknown = "draft-i-am-unknown-01.txt"
|
||||
self.write_id_file(unknown, 5000)
|
||||
self.write_draft_file(unknown, 5000)
|
||||
|
||||
clean_up_id_files()
|
||||
clean_up_draft_files()
|
||||
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.id_dir, unknown)))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.archive_dir, "unknown_ids", unknown)))
|
||||
|
@ -1116,9 +1116,9 @@ class ExpireIDsTestCase(django.test.TestCase):
|
|||
|
||||
# put file with malformed name (no revision)
|
||||
malformed = draft.name + ".txt"
|
||||
self.write_id_file(malformed, 5000)
|
||||
self.write_draft_file(malformed, 5000)
|
||||
|
||||
clean_up_id_files()
|
||||
clean_up_draft_files()
|
||||
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.id_dir, malformed)))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.archive_dir, "unknown_ids", malformed)))
|
||||
|
@ -1129,11 +1129,11 @@ class ExpireIDsTestCase(django.test.TestCase):
|
|||
draft.save()
|
||||
|
||||
txt = "%s-%s.txt" % (draft.name, draft.rev)
|
||||
self.write_id_file(txt, 5000)
|
||||
self.write_draft_file(txt, 5000)
|
||||
pdf = "%s-%s.pdf" % (draft.name, draft.rev)
|
||||
self.write_id_file(pdf, 5000)
|
||||
self.write_draft_file(pdf, 5000)
|
||||
|
||||
clean_up_id_files()
|
||||
clean_up_draft_files()
|
||||
|
||||
# txt files shouldn't be moved (for some reason)
|
||||
self.assertTrue(os.path.exists(os.path.join(self.id_dir, txt)))
|
||||
|
@ -1157,9 +1157,9 @@ class ExpireIDsTestCase(django.test.TestCase):
|
|||
|
||||
# expired without tombstone
|
||||
txt = "%s-%s.txt" % (draft.name, draft.rev)
|
||||
self.write_id_file(txt, 5000)
|
||||
self.write_draft_file(txt, 5000)
|
||||
|
||||
clean_up_id_files()
|
||||
clean_up_draft_files()
|
||||
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.id_dir, txt)))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.archive_dir, "expired_without_tombstone", txt)))
|
||||
|
@ -1169,9 +1169,9 @@ class ExpireIDsTestCase(django.test.TestCase):
|
|||
revision_before = draft.rev
|
||||
|
||||
txt = "%s-%s.txt" % (draft.name, draft.rev)
|
||||
self.write_id_file(txt, 1000) # < 1500 means tombstone
|
||||
self.write_draft_file(txt, 1000) # < 1500 means tombstone
|
||||
|
||||
clean_up_id_files()
|
||||
clean_up_draft_files()
|
||||
|
||||
self.assertTrue(not os.path.exists(os.path.join(self.id_dir, txt)))
|
||||
self.assertTrue(os.path.exists(os.path.join(self.archive_dir, "deleted_tombstones", txt)))
|
||||
|
|
|
@ -37,15 +37,20 @@ from ietf.doc import views_status_change
|
|||
from ietf.doc import views_doc
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^/?$', views_search.search_main),
|
||||
(r'^search/$', views_search.search_results),
|
||||
(r'^all/$', views_search.all),
|
||||
(r'^active/$', views_search.active),
|
||||
(r'^in-last-call/$', views_search.in_last_call),
|
||||
url(r'^rfc-status-changes/$', views_status_change.rfc_status_changes, name='rfc_status_changes'),
|
||||
url(r'^start-rfc-status-change/(?P<name>[A-Za-z0-9._+-]*)$', views_status_change.start_rfc_status_change, name='start_rfc_status_change'),
|
||||
url(r'^ad/(?P<name>[A-Za-z0-9.-]+)/$', views_search.by_ad, name="doc_search_by_ad"),
|
||||
url(r'^ad2/(?P<name>[A-Za-z0-9.-]+)/$', views_search.by_ad2, name="doc_search_by_ad2"),
|
||||
(r'^/?$', views_search.search),
|
||||
url(r'^search/$', views_search.search, name="doc_search"),
|
||||
url(r'^in-last-call/$', views_search.drafts_in_last_call, name="drafts_in_last_call"),
|
||||
url(r'^ad/(?P<name>[A-Za-z0-9.-]+)/$', views_search.drafts_for_ad, name="drafts_for_ad"),
|
||||
# (r'^all/$', views_search.all), # XXX CHECK MERGE
|
||||
# (r'^active/$', views_search.active), # XXX CHECK MERGE
|
||||
url(r'^rfc-status-changes/$', views_status_change.rfc_status_changes, name='rfc_status_changes'),
|
||||
url(r'^start-rfc-status-change/(?P<name>[A-Za-z0-9._+-]*)$', views_status_change.start_rfc_status_change, name='start_rfc_status_change'),
|
||||
url(r'^iesg/(?P<last_call_only>[A-Za-z0-9.-]+/)?$', views_search.drafts_in_iesg_process, name="drafts_in_iesg_process"),
|
||||
|
||||
# url(r'^ad2/(?P<name>[A-Za-z0-9.-]+)/$', views_search.by_ad2, name="doc_search_by_ad2"),
|
||||
|
||||
url(r'^all/$', views_search.index_all_drafts, name="index_all_drafts"),
|
||||
url(r'^active/$', views_search.index_active_drafts, name="index_active_drafts"),
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/((?P<rev>[0-9-]+)/)?$', views_doc.document_main, name="doc_view"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/history/$', views_doc.document_history, name="doc_history"),
|
||||
|
@ -56,7 +61,7 @@ urlpatterns = patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/(?P<ballot_id>[0-9]+)/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot/$', views_doc.document_ballot, name="doc_ballot"),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/doc.json$', views_doc.document_json),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballotpopup/$', views_doc.ballot_for_popup),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/ballotpopup/(?P<ballot_id>[0-9]+)/$', views_doc.ballot_popup),
|
||||
#(r'^(?P<name>[A-Za-z0-9._+-]+)/ballot.json$', views_doc.ballot_json), # legacy view
|
||||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='doc_change_state'), # IESG state
|
||||
|
@ -86,6 +91,8 @@ urlpatterns = patterns('',
|
|||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approveballot/$', views_ballot.approve_ballot, name='doc_approve_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/makelastcall/$', views_ballot.make_last_call, name='doc_make_last_call'),
|
||||
|
||||
url(r'^help/state/(?P<type>[\w-]+)/$', 'ietf.doc.views_help.state_help', name="state_help"),
|
||||
|
||||
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.wgcharter.urls')),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
|
||||
|
@ -97,4 +104,3 @@ urlpatterns += patterns('django.views.generic.simple',
|
|||
url(r'^help/state/status-change/$', 'direct_to_template', { 'template': 'doc/states.html', 'extra_context': { 'states': State.objects.filter(type="statchg").order_by("order"),'title':"RFC Status Change" } }, name='help_status_change_states'),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -64,12 +64,12 @@ def log_state_changed(request, doc, by, email_watch_list=True, note=''):
|
|||
return change
|
||||
|
||||
def log_state_changedREDESIGN(request, doc, by, prev_iesg_state, prev_iesg_tag):
|
||||
from ietf.doc.models import DocEvent
|
||||
from ietf.doc.models import DocEvent, IESG_SUBSTATE_TAGS
|
||||
|
||||
state = doc.get_state("draft-iesg")
|
||||
|
||||
state_name = state.name
|
||||
tags = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
tags = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
if tags:
|
||||
state_name += "::" + tags[0].name
|
||||
|
||||
|
|
|
@ -453,7 +453,7 @@ def defer_ballotREDESIGN(request, name):
|
|||
prev_state = doc.friendly_state()
|
||||
if doc.type_id == 'draft':
|
||||
doc.set_state(State.objects.get(used=True, type="draft-iesg", slug='defer'))
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
@ -641,7 +641,7 @@ def lastcalltextREDESIGN(request, name):
|
|||
prev = doc.get_state("draft-iesg")
|
||||
doc.set_state(State.objects.get(used=True, type="draft-iesg", slug='lc-req'))
|
||||
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
@ -1035,7 +1035,7 @@ def approve_ballotREDESIGN(request, name):
|
|||
prev = doc.get_state("draft-iesg")
|
||||
doc.set_state(new_state)
|
||||
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
|
|
@ -47,8 +47,6 @@ class ChangeStateForm(forms.Form):
|
|||
def change_state(request, name):
|
||||
pass
|
||||
|
||||
IESG_SUBSTATE_TAGS = ('point', 'ad-f-up', 'need-rev', 'extpty')
|
||||
|
||||
class ChangeStateFormREDESIGN(forms.Form):
|
||||
state = forms.ModelChoiceField(State.objects.filter(used=True, type="draft-iesg"), empty_label=None, required=True)
|
||||
substate = forms.ModelChoiceField(DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS), required=False)
|
||||
|
@ -93,7 +91,7 @@ def change_stateREDESIGN(request, name):
|
|||
|
||||
# tag handling is a bit awkward since the UI still works
|
||||
# as if IESG tags are a substate
|
||||
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
prev_tag = prev_tag[0] if prev_tag else None
|
||||
|
||||
if next_state != prev_state or tag != prev_tag:
|
||||
|
@ -144,7 +142,7 @@ def change_stateREDESIGN(request, name):
|
|||
|
||||
else:
|
||||
state = doc.get_state("draft-iesg")
|
||||
t = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
|
||||
t = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
|
||||
form = ChangeStateForm(initial=dict(state=state.pk if state else None,
|
||||
substate=t[0].pk if t else None))
|
||||
form.docname=name
|
||||
|
|
|
@ -31,29 +31,26 @@
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import re, datetime
|
||||
|
||||
from django import forms
|
||||
from django.shortcuts import render_to_response
|
||||
from django.db.models import Q
|
||||
from django.template import RequestContext
|
||||
from django.views.decorators.cache import cache_page
|
||||
from ietf.idtracker.models import IDState, IESGLogin, IDSubState, Area, InternetDraft, Rfc, IDInternal, IETFWG
|
||||
from ietf.idrfc.models import RfcIndex
|
||||
from ietf.ipr.models import IprDraft
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponsePermanentRedirect
|
||||
from ietf.idrfc.idrfc_wrapper import IdWrapper,RfcWrapper,IdRfcWrapper
|
||||
from ietf.utils import normalize_draftname
|
||||
from django.conf import settings
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
|
||||
|
||||
from ietf.idrfc.expire import expirable_draft
|
||||
from ietf.utils import normalize_draftname
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import *
|
||||
from ietf.group.models import *
|
||||
from ietf.ipr.models import IprDocAlias
|
||||
from ietf.idindex.index import active_drafts_index_by_group
|
||||
|
||||
class SearchForm(forms.Form):
|
||||
name = forms.CharField(required=False)
|
||||
rfcs = forms.BooleanField(required=False,initial=True)
|
||||
activeDrafts = forms.BooleanField(required=False,initial=True)
|
||||
oldDrafts = forms.BooleanField(required=False,initial=False)
|
||||
lucky = forms.BooleanField(required=False,initial=False)
|
||||
rfcs = forms.BooleanField(required=False, initial=True)
|
||||
activedrafts = forms.BooleanField(required=False, initial=True)
|
||||
olddrafts = forms.BooleanField(required=False, initial=False)
|
||||
|
||||
by = forms.ChoiceField(choices=[(x,x) for x in ('author','group','area','ad','state')], required=False, initial='wg', label='Foobar')
|
||||
author = forms.CharField(required=False)
|
||||
|
@ -61,7 +58,9 @@ class SearchForm(forms.Form):
|
|||
area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), empty_label="any area", required=False)
|
||||
ad = forms.ChoiceField(choices=(), required=False)
|
||||
state = forms.ModelChoiceField(State.objects.filter(type="draft-iesg"), empty_label="any state", required=False)
|
||||
subState = forms.ChoiceField(choices=(), required=False)
|
||||
substate = forms.ChoiceField(choices=(), required=False)
|
||||
|
||||
sort = forms.ChoiceField(choices=(("document", "Document"), ("title", "Title"), ("date", "Date"), ("status", "Status"), ("ipr", "Ipr"), ("ad", "AD")), required=False, widget=forms.HiddenInput)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SearchForm, self).__init__(*args, **kwargs)
|
||||
|
@ -78,54 +77,138 @@ class SearchForm(forms.Form):
|
|||
inactive_ads.sort(key=extract_last_name)
|
||||
|
||||
self.fields['ad'].choices = c = [('', 'any AD')] + [(ad.pk, ad.plain_name()) for ad in active_ads] + [('', '------------------')] + [(ad.pk, ad.name) for ad in inactive_ads]
|
||||
self.fields['subState'].choices = [('', 'any substate'), ('0', 'no substate')] + [(n.slug, n.name) for n in DocTagName.objects.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))]
|
||||
self.fields['substate'].choices = [('', 'any substate'), ('0', 'no substate')] + [(n.slug, n.name) for n in DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS)]
|
||||
|
||||
def clean_name(self):
|
||||
value = self.cleaned_data.get('name','')
|
||||
return normalize_draftname(value)
|
||||
|
||||
def clean(self):
|
||||
q = self.cleaned_data
|
||||
# Reset query['by'] if needed
|
||||
if 'by' not in q:
|
||||
q['by'] = None
|
||||
else:
|
||||
for k in ('author','group','area','ad'):
|
||||
if (q['by'] == k) and (k not in q or not q[k]):
|
||||
if 'by' in q:
|
||||
for k in ('author', 'group', 'area', 'ad'):
|
||||
if q['by'] == k and not q.get(k):
|
||||
q['by'] = None
|
||||
if (q['by'] == 'state') and (not 'state' in q or not 'subState' in q or not (q['state'] or q['subState'])):
|
||||
if q['by'] == 'state' and not (q.get("state") or q.get('substate')):
|
||||
q['by'] = None
|
||||
# Reset other fields
|
||||
for k in ('author','group','area','ad'):
|
||||
if q['by'] != k:
|
||||
self.data[k] = ""
|
||||
for k in ('author','group', 'area', 'ad'):
|
||||
if k != q['by']:
|
||||
q[k] = ""
|
||||
if q['by'] != 'state':
|
||||
self.data['state'] = ""
|
||||
self.data['subState'] = ""
|
||||
q['state'] = ""
|
||||
q['subState'] = ""
|
||||
q['state'] = q['substate'] = None
|
||||
return q
|
||||
|
||||
def search_query(query_original, sort_by=None):
|
||||
query = dict(query_original.items())
|
||||
drafts = query['activeDrafts'] or query['oldDrafts']
|
||||
if (not drafts) and (not query['rfcs']):
|
||||
def wrap_value(v):
|
||||
return lambda: v
|
||||
|
||||
def fill_in_search_attributes(docs):
|
||||
# fill in some attributes for the search results to save some
|
||||
# hairy template code and avoid repeated SQL queries - remaining
|
||||
# queries we don't handle here are mostly implicit many-to-many
|
||||
# relations for which there is poor support in Django 1.2
|
||||
|
||||
docs_dict = dict((d.pk, d) for d in docs)
|
||||
doc_ids = docs_dict.keys()
|
||||
|
||||
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=doc_ids).values_list("document_id", "name"))
|
||||
|
||||
# latest event cache
|
||||
event_types = ("published_rfc",
|
||||
"changed_ballot_position",
|
||||
"started_iesg_process",
|
||||
"new_revision")
|
||||
for d in docs:
|
||||
d.latest_event_cache = dict()
|
||||
for e in event_types:
|
||||
d.latest_event_cache[e] = None
|
||||
|
||||
for e in DocEvent.objects.filter(doc__in=doc_ids, type__in=event_types).order_by('time'):
|
||||
docs_dict[e.doc_id].latest_event_cache[e.type] = e
|
||||
|
||||
# IPR
|
||||
for d in docs:
|
||||
d.iprs = []
|
||||
|
||||
ipr_docaliases = IprDocAlias.objects.filter(doc_alias__document__in=doc_ids).select_related('doc_alias')
|
||||
for a in ipr_docaliases:
|
||||
docs_dict[a.doc_alias.document_id].iprs.append(a)
|
||||
|
||||
# telechat date, can't do this with above query as we need to get TelechatDocEvents out
|
||||
seen = set()
|
||||
for e in TelechatDocEvent.objects.filter(doc__in=doc_ids, type="scheduled_for_telechat").order_by('-time'):
|
||||
if e.doc_id not in seen:
|
||||
d = docs_dict[e.doc_id]
|
||||
d.telechat_date = wrap_value(d.telechat_date(e))
|
||||
seen.add(e.doc_id)
|
||||
|
||||
# misc
|
||||
for d in docs:
|
||||
# emulate canonical name which is used by a lot of the utils
|
||||
d.canonical_name = wrap_value(rfc_aliases[d.pk] if d.pk in rfc_aliases else d.name)
|
||||
|
||||
if d.rfc_number() != None and d.latest_event_cache["published_rfc"]:
|
||||
d.latest_revision_date = d.latest_event_cache["published_rfc"].time
|
||||
elif d.latest_event_cache["new_revision"]:
|
||||
d.latest_revision_date = d.latest_event_cache["new_revision"].time
|
||||
else:
|
||||
d.latest_revision_date = d.time
|
||||
|
||||
if d.get_state_slug() == "rfc":
|
||||
d.search_heading = "RFCs"
|
||||
elif d.get_state_slug() == "active":
|
||||
d.search_heading = "Active Internet-Drafts"
|
||||
else:
|
||||
d.search_heading = "Old Internet-Drafts"
|
||||
|
||||
d.expirable = expirable_draft(d)
|
||||
|
||||
if d.get_state_slug() != "rfc":
|
||||
d.milestones = d.groupmilestone_set.filter(state="active").order_by("time").select_related("group")
|
||||
|
||||
|
||||
|
||||
# RFCs
|
||||
|
||||
# errata
|
||||
erratas = set(Document.objects.filter(tags="errata", name__in=rfc_aliases.keys()).distinct().values_list("name", flat=True))
|
||||
for d in docs:
|
||||
d.has_errata = d.name in erratas
|
||||
|
||||
# obsoleted/updated by
|
||||
for a in rfc_aliases:
|
||||
d = docs_dict[a]
|
||||
d.obsoleted_by_list = []
|
||||
d.updated_by_list = []
|
||||
|
||||
xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(),
|
||||
relationship__in=("obs", "updates")).select_related('target__document_id')
|
||||
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc",
|
||||
document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name'))
|
||||
for rel in xed_by:
|
||||
d = docs_dict[rel.target.document_id]
|
||||
if rel.relationship_id == "obs":
|
||||
l = d.obsoleted_by_list
|
||||
elif rel.relationship_id == "updates":
|
||||
l = d.updated_by_list
|
||||
l.append(rel_rfc_aliases[rel.source_id].upper())
|
||||
l.sort()
|
||||
|
||||
|
||||
def retrieve_search_results(form):
|
||||
"""Takes a validated SearchForm and return the results."""
|
||||
if not form.is_valid():
|
||||
raise ValueError("SearchForm doesn't validate: %s" % form.errors)
|
||||
|
||||
query = form.cleaned_data
|
||||
|
||||
if not (query['activedrafts'] or query['olddrafts'] or query['rfcs']):
|
||||
return ([], {})
|
||||
|
||||
# Non-ASCII strings don't match anything; this check
|
||||
# is currently needed to avoid complaints from MySQL.
|
||||
# FIXME: this should be fixed with MySQL if it's still a problem?
|
||||
for k in ['name','author','group']:
|
||||
try:
|
||||
tmp = str(query.get(k, ''))
|
||||
except:
|
||||
query[k] = '*NOSUCH*'
|
||||
|
||||
# Start by search InternetDrafts
|
||||
idresults = []
|
||||
rfcresults = []
|
||||
MAX = 500
|
||||
|
||||
docs = InternetDraft.objects.all()
|
||||
docs = Document.objects.filter(type="draft")
|
||||
|
||||
# name
|
||||
if query["name"]:
|
||||
|
@ -136,9 +219,9 @@ def search_query(query_original, sort_by=None):
|
|||
allowed_states = []
|
||||
if query["rfcs"]:
|
||||
allowed_states.append("rfc")
|
||||
if query["activeDrafts"]:
|
||||
if query["activedrafts"]:
|
||||
allowed_states.append("active")
|
||||
if query["oldDrafts"]:
|
||||
if query["olddrafts"]:
|
||||
allowed_states.extend(['repl', 'expired', 'auth-rm', 'ietf-rm'])
|
||||
|
||||
docs = docs.filter(states__type="draft", states__slug__in=allowed_states)
|
||||
|
@ -146,7 +229,6 @@ def search_query(query_original, sort_by=None):
|
|||
# radio choices
|
||||
by = query["by"]
|
||||
if by == "author":
|
||||
# FIXME: this is full name, not last name as hinted in the HTML
|
||||
docs = docs.filter(authors__person__name__icontains=query["author"])
|
||||
elif by == "group":
|
||||
docs = docs.filter(group__acronym=query["group"])
|
||||
|
@ -158,66 +240,20 @@ def search_query(query_original, sort_by=None):
|
|||
elif by == "state":
|
||||
if query["state"]:
|
||||
docs = docs.filter(states=query["state"])
|
||||
if query["subState"]:
|
||||
docs = docs.filter(tags=query["subState"])
|
||||
if query["substate"]:
|
||||
docs = docs.filter(tags=query["substate"])
|
||||
|
||||
# evaluate and fill in values with aggregate queries to avoid
|
||||
# too many individual queries
|
||||
# evaluate and fill in attribute results immediately to cut down
|
||||
# the number of queries
|
||||
results = list(docs.select_related("states", "ad", "ad__person", "std_level", "intended_std_level", "group", "stream")[:MAX])
|
||||
|
||||
rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[r.pk for r in results]).values_list("document_id", "name"))
|
||||
# canonical name
|
||||
for r in results:
|
||||
if r.pk in rfc_aliases:
|
||||
# lambda weirdness works around lambda binding in local for loop scope
|
||||
r.canonical_name = (lambda x: lambda: x)(rfc_aliases[r.pk])
|
||||
else:
|
||||
r.canonical_name = (lambda x: lambda: x)(r.name)
|
||||
|
||||
result_map = dict((r.pk, r) for r in results)
|
||||
|
||||
# events
|
||||
event_types = ("published_rfc",
|
||||
"changed_ballot_position",
|
||||
"started_iesg_process",
|
||||
"new_revision")
|
||||
for d in rfc_aliases.keys():
|
||||
for e in event_types:
|
||||
setattr(result_map[d], e, None)
|
||||
|
||||
for e in DocEvent.objects.filter(doc__in=rfc_aliases.keys(), type__in=event_types).order_by('-time'):
|
||||
r = result_map[e.doc_id]
|
||||
if not getattr(r, e.type):
|
||||
# sets e.g. r.published_date = e for use in proxy wrapper
|
||||
setattr(r, e.type, e)
|
||||
|
||||
# obsoleted/updated by
|
||||
for d in rfc_aliases:
|
||||
r = result_map[d]
|
||||
r.obsoleted_by_list = []
|
||||
r.updated_by_list = []
|
||||
|
||||
xed_by = RelatedDocument.objects.filter(target__name__in=rfc_aliases.values(), relationship__in=("obs", "updates")).select_related('target__document_id')
|
||||
rel_rfc_aliases = dict(DocAlias.objects.filter(name__startswith="rfc", document__in=[rel.source_id for rel in xed_by]).values_list('document_id', 'name'))
|
||||
for rel in xed_by:
|
||||
r = result_map[rel.target.document_id]
|
||||
if rel.relationship_id == "obs":
|
||||
attr = "obsoleted_by_list"
|
||||
else:
|
||||
attr = "updated_by_list"
|
||||
|
||||
getattr(r, attr).append(int(rel_rfc_aliases[rel.source_id][3:]))
|
||||
|
||||
fill_in_search_attributes(results)
|
||||
|
||||
# sort
|
||||
def sort_key(d):
|
||||
res = []
|
||||
|
||||
canonical = d.canonical_name()
|
||||
if canonical.startswith('rfc'):
|
||||
rfc_num = int(canonical[3:])
|
||||
else:
|
||||
rfc_num = None
|
||||
rfc_num = d.rfc_number()
|
||||
|
||||
if rfc_num != None:
|
||||
res.append(2)
|
||||
|
@ -226,20 +262,20 @@ def search_query(query_original, sort_by=None):
|
|||
else:
|
||||
res.append(3)
|
||||
|
||||
if sort_by == "title":
|
||||
if query["sort"] == "title":
|
||||
res.append(d.title)
|
||||
elif sort_by == "date":
|
||||
res.append(str(d.revision_date or datetime.date(1990, 1, 1)))
|
||||
elif sort_by == "status":
|
||||
elif query["sort"] == "date":
|
||||
res.append(str(d.latest_revision_date))
|
||||
elif query["sort"] == "status":
|
||||
if rfc_num != None:
|
||||
res.append(rfc_num)
|
||||
res.append(int(rfc_num))
|
||||
else:
|
||||
res.append(d.get_state().order)
|
||||
elif sort_by == "ipr":
|
||||
res.append(d.name)
|
||||
elif sort_by == "ad":
|
||||
res.append(d.get_state().order if d.get_state() else None)
|
||||
elif query["sort"] == "ipr":
|
||||
res.append(len(d.iprs))
|
||||
elif query["sort"] == "ad":
|
||||
if rfc_num != None:
|
||||
res.append(rfc_num)
|
||||
res.append(int(rfc_num))
|
||||
elif d.get_state_slug() == "active":
|
||||
if d.get_state("draft-iesg"):
|
||||
res.append(d.get_state("draft-iesg").order)
|
||||
|
@ -247,286 +283,177 @@ def search_query(query_original, sort_by=None):
|
|||
res.append(0)
|
||||
else:
|
||||
if rfc_num != None:
|
||||
res.append(rfc_num)
|
||||
res.append(int(rfc_num))
|
||||
else:
|
||||
res.append(canonical)
|
||||
res.append(d.canonical_name())
|
||||
|
||||
return res
|
||||
|
||||
results.sort(key=sort_key)
|
||||
|
||||
# fill in a meta dict with some information for rendering the result table
|
||||
meta = {}
|
||||
if len(docs) == MAX:
|
||||
if len(results) == MAX:
|
||||
meta['max'] = MAX
|
||||
if query['by']:
|
||||
meta['advanced'] = True
|
||||
meta['by'] = query['by']
|
||||
meta['advanced'] = bool(query['by'])
|
||||
|
||||
# finally wrap in old wrappers
|
||||
meta['headers'] = [{'title': 'Document', 'key':'document'},
|
||||
{'title': 'Title', 'key':'title'},
|
||||
{'title': 'Date', 'key':'date'},
|
||||
{'title': 'Status', 'key':'status', 'colspan':'2'},
|
||||
{'title': 'IPR', 'key':'ipr'},
|
||||
{'title': 'Area Director', 'key':'ad'}]
|
||||
|
||||
wrapped_results = []
|
||||
for r in results:
|
||||
draft = None
|
||||
rfc = None
|
||||
if not r.name.startswith('rfc'):
|
||||
draft = IdWrapper(r)
|
||||
if r.name.startswith('rfc') or r.pk in rfc_aliases:
|
||||
rfc = RfcWrapper(r)
|
||||
wrapped_results.append(IdRfcWrapper(draft, rfc))
|
||||
if hasattr(form.data, "urlencode"): # form was fed a Django QueryDict, not local plain dict
|
||||
d = form.data.copy()
|
||||
for h in meta['headers']:
|
||||
d["sort"] = h["key"]
|
||||
h["sort_url"] = "?" + d.urlencode()
|
||||
if h['key'] == query.get('sort'):
|
||||
h['sorted'] = True
|
||||
|
||||
return (wrapped_results, meta)
|
||||
|
||||
return (results, meta)
|
||||
|
||||
def generate_query_string(request, ignore_list):
|
||||
"""Recreates the parameter string from the given request, and
|
||||
returns it as a string.
|
||||
Any parameter names present in ignore_list shall not be put
|
||||
in the result string.
|
||||
"""
|
||||
params = []
|
||||
for i in request.GET:
|
||||
if not i in ignore_list:
|
||||
params.append(i + "=" + request.GET[i])
|
||||
return "?" + "&".join(params)
|
||||
|
||||
def search_results(request):
|
||||
if len(request.REQUEST.items()) == 0:
|
||||
return search_main(request)
|
||||
form = SearchForm(dict(request.REQUEST.items()))
|
||||
if not form.is_valid():
|
||||
return HttpResponseBadRequest("form not valid?", mimetype="text/plain")
|
||||
def search(request):
|
||||
if request.GET:
|
||||
# backwards compatibility
|
||||
get_params = request.GET.copy()
|
||||
if 'activeDrafts' in request.GET:
|
||||
get_params['activedrafts'] = request.GET['activeDrafts']
|
||||
if 'oldDrafts' in request.GET:
|
||||
get_params['olddrafts'] = request.GET['oldDrafts']
|
||||
if 'subState' in request.GET:
|
||||
get_params['substate'] = request.GET['subState']
|
||||
|
||||
sort_by = None
|
||||
if "sortBy" in request.GET:
|
||||
sort_by = request.GET["sortBy"]
|
||||
form = SearchForm(get_params)
|
||||
if not form.is_valid():
|
||||
return HttpResponseBadRequest("form not valid: %s" % form.errors)
|
||||
|
||||
(results,meta) = search_query(form.cleaned_data, sort_by)
|
||||
|
||||
meta['searching'] = True
|
||||
meta['by'] = form.cleaned_data['by']
|
||||
meta['rqps'] = generate_query_string(request, ['sortBy'])
|
||||
# With a later Django we can do this from the template (incude with tag)
|
||||
# Pass the headers and their sort key names
|
||||
meta['hdrs'] = [{'htitle': 'Document', 'htype':'doc'},
|
||||
{'htitle': 'Title', 'htype':'title'},
|
||||
{'htitle': 'Date', 'htype':'date'},
|
||||
{'htitle': 'Status', 'htype':'status', 'colspan':'2'},
|
||||
{'htitle': 'IPR', 'htype':'ipr'},
|
||||
{'htitle': 'Ad/Shepherd', 'htype':'ad'}]
|
||||
|
||||
# Make sure we know which one is selected (for visibility later)
|
||||
if sort_by:
|
||||
for hdr in meta['hdrs']:
|
||||
if hdr['htype'] == sort_by:
|
||||
hdr['selected'] = True
|
||||
|
||||
if 'ajax' in request.REQUEST and request.REQUEST['ajax']:
|
||||
return render_to_response('idrfc/search_results.html', {'docs':results, 'meta':meta}, context_instance=RequestContext(request))
|
||||
elif form.cleaned_data['lucky'] and len(results)==1:
|
||||
doc = results[0]
|
||||
if doc.id:
|
||||
return HttpResponsePermanentRedirect(doc.id.get_absolute_url())
|
||||
else:
|
||||
return HttpResponsePermanentRedirect(doc.rfc.get_absolute_url())
|
||||
results, meta = retrieve_search_results(form)
|
||||
meta['searching'] = True
|
||||
else:
|
||||
return render_to_response('idrfc/search_main.html', {'form':form, 'docs':results,'meta':meta}, context_instance=RequestContext(request))
|
||||
|
||||
form = SearchForm()
|
||||
results = []
|
||||
meta = { 'by': None, 'advanced': False, 'searching': False }
|
||||
|
||||
def search_main(request):
|
||||
form = SearchForm()
|
||||
return render_to_response('idrfc/search_main.html', {'form':form}, context_instance=RequestContext(request))
|
||||
return render_to_response('doc/search.html',
|
||||
{'form':form, 'docs':results, 'meta':meta, 'show_add_to_list': True },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def by_ad(request, name):
|
||||
ad_id = None
|
||||
ad_name = None
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
responsible = Document.objects.values_list('ad', flat=True).distinct()
|
||||
for p in Person.objects.filter(Q(role__name__in=("pre-ad", "ad"),
|
||||
role__group__type="area",
|
||||
role__group__state="active")
|
||||
| Q(pk__in=responsible)).distinct():
|
||||
if name == p.full_name_as_key():
|
||||
ad_id = p.id
|
||||
ad_name = p.plain_name()
|
||||
break
|
||||
else:
|
||||
for i in IESGLogin.objects.filter(user_level__in=[1,2]):
|
||||
iname = str(i).lower().replace(' ','.')
|
||||
if name == iname:
|
||||
ad_id = i.id
|
||||
ad_name = str(i)
|
||||
break
|
||||
if not ad_id:
|
||||
raise Http404
|
||||
form = SearchForm({'by':'ad','ad':ad_id,
|
||||
'rfcs':'on', 'activeDrafts':'on', 'oldDrafts':'on'})
|
||||
if not form.is_valid():
|
||||
raise ValueError("form did not validate")
|
||||
(results,meta) = search_query(form.cleaned_data)
|
||||
results.sort(key=lambda obj: obj.view_sort_key_byad())
|
||||
return render_to_response('idrfc/by_ad.html', {'form':form, 'docs':results,'meta':meta, 'ad_name':ad_name}, context_instance=RequestContext(request))
|
||||
|
||||
def ad_dashboard_group(doc):
|
||||
|
||||
if doc.type.slug=='draft':
|
||||
if doc.get_state_slug('draft') == 'rfc':
|
||||
return 'RFC'
|
||||
elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg'):
|
||||
return '%s Internet-Draft' % doc.get_state('draft-iesg').name
|
||||
else:
|
||||
return '%s Internet-Draft' % doc.get_state('draft').name
|
||||
elif doc.type.slug=='conflrev':
|
||||
if doc.get_state_slug('conflrev') in ('appr-reqnopub-sent','appr-noprob-sent'):
|
||||
return 'Approved Conflict Review'
|
||||
elif doc.get_state_slug('conflrev') in ('appr-reqnopub-pend','appr-noprob-pend','appr-reqnopub-pr','appr-noprob-pr'):
|
||||
return "%s Conflict Review" % State.objects.get(type__slug='draft-iesg',slug='approved')
|
||||
else:
|
||||
return '%s Conflict Review' % doc.get_state('conflrev')
|
||||
elif doc.type.slug=='statchg':
|
||||
if doc.get_state_slug('statchg') in ('appr-sent',):
|
||||
return 'Approved Status Change'
|
||||
if doc.get_state_slug('statchg') in ('appr-pend','appr-pr'):
|
||||
return '%s Status Change' % State.objects.get(type__slug='draft-iesg',slug='approved')
|
||||
else:
|
||||
return '%s Status Change' % doc.get_state('statchg')
|
||||
elif doc.type.slug=='charter':
|
||||
if doc.get_state_slug('charter') == 'approved':
|
||||
return "Approved Charter"
|
||||
else:
|
||||
return '%s Charter' % doc.get_state('charter')
|
||||
else:
|
||||
return "Document"
|
||||
|
||||
def ad_dashboard_sort_key(doc):
|
||||
|
||||
if doc.type.slug=='draft' and doc.get_state_slug('draft') == 'rfc':
|
||||
return "21%04d" % int(doc.rfc_number())
|
||||
if doc.type.slug=='statchg' and doc.get_state_slug('statchg') == 'appr-sent':
|
||||
return "22%d" % 0 # TODO - get the date of the transition into this state here
|
||||
if doc.type.slug=='conflrev' and doc.get_state_slug('conflrev') in ('appr-reqnopub-sent','appr-noprob-sent'):
|
||||
return "23%d" % 0 # TODO - get the date of the transition into this state here
|
||||
if doc.type.slug=='charter' and doc.get_state_slug('charter') == 'approved':
|
||||
return "24%d" % 0 # TODO - get the date of the transition into this state here
|
||||
|
||||
seed = ad_dashboard_group(doc)
|
||||
|
||||
if doc.type.slug=='conflrev' and doc.get_state_slug('conflrev') == 'adrev':
|
||||
state = State.objects.get(type__slug='draft-iesg',slug='ad-eval')
|
||||
return "1%d%s" % (state.order,seed)
|
||||
|
||||
if doc.type.slug=='charter':
|
||||
if doc.get_state_slug('charter') in ('notrev','infrev'):
|
||||
return "100%s" % seed
|
||||
elif doc.get_state_slug('charter') == 'intrev':
|
||||
state = State.objects.get(type__slug='draft-iesg',slug='ad-eval')
|
||||
return "1%d%s" % (state.order,seed)
|
||||
elif doc.get_state_slug('charter') == 'extrev':
|
||||
state = State.objects.get(type__slug='draft-iesg',slug='lc')
|
||||
return "1%d%s" % (state.order,seed)
|
||||
elif doc.get_state_slug('charter') == 'iesgrev':
|
||||
state = State.objects.get(type__slug='draft-iesg',slug='iesg-eva')
|
||||
return "1%d%s" % (state.order,seed)
|
||||
|
||||
if doc.type.slug=='statchg' and doc.get_state_slug('statchg') == 'adrev':
|
||||
state = State.objects.get(type__slug='draft-iesg',slug='ad-eval')
|
||||
return "1%d%s" % (state.order,seed)
|
||||
|
||||
if seed.startswith('Needs Shepherd'):
|
||||
return "100%s" % seed
|
||||
if seed.endswith(' Document'):
|
||||
seed = seed[:-9]
|
||||
elif seed.endswith(' Internet-Draft'):
|
||||
seed = seed[:-15]
|
||||
elif seed.endswith(' Conflict Review'):
|
||||
seed = seed[:-16]
|
||||
elif seed.endswith(' Status Change'):
|
||||
seed = seed[:-14]
|
||||
state = State.objects.filter(type__slug='draft-iesg',name=seed)
|
||||
if state:
|
||||
ageseconds = 0
|
||||
changetime= doc.latest_event(type='changed_document')
|
||||
if changetime:
|
||||
ad = (datetime.datetime.now()-doc.latest_event(type='changed_document').time)
|
||||
ageseconds = (ad.microseconds + (ad.seconds + ad.days * 24 * 3600) * 10**6) / 10**6
|
||||
return "1%d%s%s%010d" % (state[0].order,seed,doc.type.slug,ageseconds)
|
||||
|
||||
return "3%s" % seed
|
||||
|
||||
def by_ad2(request, name):
|
||||
def drafts_for_ad(request, name):
|
||||
ad = None
|
||||
responsible = Document.objects.values_list('ad', flat=True).distinct()
|
||||
ad_id = None
|
||||
for p in Person.objects.filter(Q(role__name__in=("pre-ad", "ad"),
|
||||
role__group__type="area",
|
||||
role__group__state="active")
|
||||
| Q(pk__in=responsible)).distinct():
|
||||
if name == p.full_name_as_key():
|
||||
ad_id = p.id
|
||||
ad_name = p.plain_name()
|
||||
ad = p
|
||||
break
|
||||
|
||||
if not ad_id:
|
||||
if not ad:
|
||||
raise Http404
|
||||
form = SearchForm({'by':'ad','ad': ad.id,
|
||||
'rfcs':'on', 'activedrafts':'on', 'olddrafts':'on',
|
||||
'sort': 'status'})
|
||||
results, meta = retrieve_search_results(form)
|
||||
|
||||
docqueryset = Document.objects.filter(ad__id=ad_id)
|
||||
docs=[]
|
||||
for doc in docqueryset:
|
||||
doc.ad_dashboard_sort_key = ad_dashboard_sort_key(doc)
|
||||
doc.ad_dashboard_group = ad_dashboard_group(doc)
|
||||
if doc.get_state_slug() == 'rfc':
|
||||
doc.display_date = doc.latest_event(type='published_rfc').time
|
||||
else:
|
||||
revision = doc.latest_event(type='new_revision')
|
||||
if revision:
|
||||
doc.display_date = revision.time
|
||||
# This might be better handled as something Documents know about themselves
|
||||
now = datetime.datetime.now()
|
||||
doc.can_expire = (doc.type.slug=='draft' and doc.get_state_slug('draft')=='active' and ( not doc.get_state('draft-iesg') or doc.get_state('draft-iesg').order >= 42) and doc.expires>now)
|
||||
if doc.get_state_slug('draft') == 'rfc':
|
||||
doc.obsoleted_by = ", ".join([ 'RFC %04d' % int(rel.source.rfc_number()) for alias in doc.docalias_set.all() for rel in alias.relateddocument_set.filter(relationship='obsoletes') ] )
|
||||
doc.updated_by = ", ".join([ 'RFC %04d' % int(rel.source.rfc_number()) for alias in doc.docalias_set.all() for rel in alias.relateddocument_set.filter(relationship='updates') ] )
|
||||
doc.has_errata = bool(doc.tags.filter(slug="errata"))
|
||||
else:
|
||||
s = doc.get_state("draft-rfceditor")
|
||||
if s:
|
||||
# extract possible extra annotations
|
||||
tags = doc.tags.filter(slug__in=("iana", "ref"))
|
||||
doc.rfc_editor_state = "*".join([s.name] + [t.slug.upper() for t in tags])
|
||||
if doc.type.slug == 'draft':
|
||||
doc.iprCount = IprDraft.objects.filter(document=doc, ipr__status__in=[1,3]).count()
|
||||
doc.iprUrl = "/ipr/search?option=document_search&id_document_tag=%s" % doc.name
|
||||
docs.append(doc)
|
||||
docs.sort(key=ad_dashboard_sort_key)
|
||||
return render_to_response('idrfc/by_ad2.html',{'docs':docs,'ad_name':ad_name}, context_instance=RequestContext(request))
|
||||
for d in results:
|
||||
if d.get_state_slug() == "active":
|
||||
iesg_state = d.get_state("draft-iesg")
|
||||
if iesg_state:
|
||||
if iesg_state.slug == "dead":
|
||||
d.search_heading = "IESG Dead Internet-Drafts"
|
||||
else:
|
||||
d.search_heading = "%s Internet-Drafts" % iesg_state.name
|
||||
|
||||
return render_to_response('doc/drafts_for_ad.html',
|
||||
{ 'form':form, 'docs':results, 'meta':meta, 'ad_name': ad.plain_name() },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@cache_page(15*60) # 15 minutes
|
||||
def all(request):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
active = (dict(filename=n) for n in InternetDraft.objects.filter(states__type="draft", states__slug="active").order_by("name").values_list('name', flat=True))
|
||||
rfc1 = (dict(filename=d, rfc_number=int(n[3:])) for d, n in DocAlias.objects.filter(document__states__type="draft", document__states__slug="rfc", name__startswith="rfc").exclude(document__name__startswith="rfc").order_by("document__name").values_list('document__name','name').distinct())
|
||||
rfc2 = (dict(rfc_number=r, draft=None) for r in sorted(int(n[3:]) for n in Document.objects.filter(type="draft", name__startswith="rfc").values_list('name', flat=True)))
|
||||
dead = InternetDraft.objects.exclude(states__type="draft", states__slug__in=("active", "rfc")).select_related("states").order_by("name")
|
||||
def drafts_in_last_call(request):
|
||||
lc_state = State.objects.get(type="draft-iesg", slug="lc").pk
|
||||
form = SearchForm({'by':'state','state': lc_state, 'rfcs':'on', 'activedrafts':'on'})
|
||||
results, meta = retrieve_search_results(form)
|
||||
|
||||
return render_to_response('doc/drafts_in_last_call.html',
|
||||
{ 'form':form, 'docs':results, 'meta':meta },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def drafts_in_iesg_process(request, last_call_only=None):
|
||||
if last_call_only:
|
||||
states = State.objects.filter(type="draft-iesg", slug__in=("lc", "writeupw", "goaheadw"))
|
||||
title = "Documents in Last Call"
|
||||
else:
|
||||
active = InternetDraft.objects.all().filter(status=1).order_by("filename").values('filename')
|
||||
rfc1 = InternetDraft.objects.all().filter(status=3).order_by("filename").values('filename','rfc_number')
|
||||
rfc_numbers1 = InternetDraft.objects.all().filter(status=3).values_list('rfc_number', flat=True)
|
||||
rfc2 = RfcIndex.objects.all().exclude(rfc_number__in=rfc_numbers1).order_by('rfc_number').values('rfc_number','draft')
|
||||
dead = InternetDraft.objects.all().exclude(status__in=[1,3]).order_by("filename").select_related('status__status')
|
||||
return render_to_response('idrfc/all.html', {'active':active, 'rfc1':rfc1, 'rfc2':rfc2, 'dead':dead}, context_instance=RequestContext(request))
|
||||
states = State.objects.filter(type="draft-iesg").exclude(slug__in=('pub', 'dead', 'watching', 'rfcqueue'))
|
||||
title = "Documents in IESG process"
|
||||
|
||||
@cache_page(15*60) # 15 minutes
|
||||
def active(request):
|
||||
groups = IETFWG.objects.exclude(group_acronym=1027)
|
||||
individual = IETFWG.objects.get(group_acronym=1027)
|
||||
return render_to_response("idrfc/active.html", {'groups':groups,'individual':individual}, context_instance=RequestContext(request))
|
||||
grouped_docs = []
|
||||
|
||||
def in_last_call(request):
|
||||
|
||||
lcdocs = []
|
||||
for s in states.order_by("order"):
|
||||
docs = Document.objects.filter(type="draft", states=s).distinct().order_by("time").select_related("ad", "group", "group__parent")
|
||||
if docs:
|
||||
if s.slug == "lc":
|
||||
for d in docs:
|
||||
e = d.latest_event(LastCallDocEvent, type="sent_last_call")
|
||||
d.lc_expires = e.expires if e else datetime.datetime.min
|
||||
docs = list(docs)
|
||||
docs.sort(key=lambda d: d.lc_expires)
|
||||
|
||||
for p in InternetDraft.objects.all().filter(idinternal__primary_flag=1).filter(idinternal__cur_state__state='In Last Call'):
|
||||
if (p.idinternal.rfc_flag):
|
||||
lcdocs.append(IdRfcWrapper(None,RfcWrapper(p)))
|
||||
else:
|
||||
lcdocs.append(IdRfcWrapper(IdWrapper(p),None))
|
||||
grouped_docs.append((s, docs))
|
||||
|
||||
return render_to_response("idrfc/in_last_call.html", {'lcdocs':lcdocs}, context_instance=RequestContext(request))
|
||||
return render_to_response('doc/drafts_in_iesg_process.html', {
|
||||
"grouped_docs": grouped_docs,
|
||||
"title": title,
|
||||
"last_call_only": last_call_only,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
def index_all_drafts(request):
|
||||
# try to be efficient since this view returns a lot of data
|
||||
categories = []
|
||||
|
||||
for s in ("active", "rfc", "expired", "repl", "auth-rm", "ietf-rm"):
|
||||
state = State.objects.get(type="draft", slug=s)
|
||||
|
||||
if state.slug == "rfc":
|
||||
heading = "RFCs"
|
||||
elif state.slug in ("ietf-rm", "auth-rm"):
|
||||
heading = "Internet-Drafts %s" % state.name
|
||||
else:
|
||||
heading = "%s Internet-Drafts" % state.name
|
||||
|
||||
draft_names = DocAlias.objects.filter(document__states=state).values_list("name", "document")
|
||||
|
||||
names = []
|
||||
names_to_skip = set()
|
||||
for name, doc in draft_names:
|
||||
sort_key = name
|
||||
if name != doc:
|
||||
if not name.startswith("rfc"):
|
||||
name, doc = doc, name
|
||||
names_to_skip.add(doc)
|
||||
|
||||
if name.startswith("rfc"):
|
||||
name = name.upper()
|
||||
sort_key = -int(name[3:])
|
||||
|
||||
names.append((name, sort_key))
|
||||
|
||||
names.sort(key=lambda t: t[1])
|
||||
|
||||
names = ['<a href="/doc/' + name + '/">' + name +'</a>'
|
||||
for name, _ in names if name not in names_to_skip]
|
||||
|
||||
categories.append((state,
|
||||
heading,
|
||||
len(names),
|
||||
"<br>".join(names)
|
||||
))
|
||||
return render_to_response('doc/index_all_drafts.html', { "categories": categories },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def index_active_drafts(request):
|
||||
groups = active_drafts_index_by_group()
|
||||
|
||||
return render_to_response("doc/index_active_drafts.html", { 'groups': groups }, context_instance=RequestContext(request))
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
form_for_model(IDInternal) will autogenerate form elemnts to edit the model
|
||||
|
||||
class ImageAddForm(BaseForm):
|
||||
|
||||
def __init__(self, *args, name=None, **kwargs):
|
||||
super(ImageAddForm, self).__init__(*args, **kwargs)
|
||||
self.fields['category'].choices=(('a','a'),)
|
||||
# create filter based on name=
|
||||
|
||||
ImageForm = form_for_model(Image, form=ImageAddForm)
|
||||
foo = ImageForm(name='foo')
|
||||
|
||||
|
||||
|
||||
To get from draft to author list:
|
||||
|
||||
>>> d = a[5]
|
||||
>>> print d
|
||||
draft-fenner-zinin-rtg-standard-reqts
|
||||
>>> print d.authors.all()
|
||||
[<IDAuthors: IDAuthors object>, <IDAuthors: IDAuthors object>]
|
||||
>>> l=d.authors.all()
|
||||
>>> print l[0].person
|
||||
Bill Fenner
|
||||
>>> print l[0].person.emailaddresses_set.filter(priority=d.id_document_tag)
|
||||
[<EmailAddresses: EmailAddresses object>]
|
||||
>>> print l[0].person.emailaddresses_set.filter(priority=d.id_document_tag)[0].ail_address
|
||||
fenner@research.att.com
|
||||
|
||||
IDAuthors should have an auxilliary function for this.
|
||||
It's the one that has the person linkage and knows the document.
|
||||
|
||||
|
||||
--
|
||||
we should use a variant of django-registration.
|
||||
http://www.stonemind.net/blog/2007/04/13/django-registration-for-newbies/
|
||||
|
||||
1. verify email address with round trip
|
||||
2. if there's a row in iesg_login, use that username
|
||||
(? liaison tool logins ?)
|
||||
otherwise, force the email address
|
||||
3. get a password and create the user
|
||||
(this is almost the same as resetting the password)
|
||||
4. find the person_or_org_info row, associate that with
|
||||
the user row
|
||||
|
||||
--
|
||||
|
||||
<ubernostrum> Both the regular and date-base object_detail can take either an
|
||||
+object_id, or a slug/slug_field combo.
|
||||
<ubernostrum> So use the username as the "slug" and specify 'username' as the
|
||||
+'slug_field' argument.
|
||||
|
||||
http://www.b-list.org/weblog/2006/11/16/django-tips-get-most-out-generic-views
|
||||
|
||||
newly learned: 'slug_field' just gets passed so can be otherdb__username
|
|
@ -1,72 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
|
||||
from django.utils.feedgenerator import Atom1Feed
|
||||
from ietf.idtracker.models import IDInternal
|
||||
import datetime
|
||||
import re
|
||||
|
||||
class DocumentComments(Feed):
|
||||
feed_type = Atom1Feed
|
||||
def get_object(self, bits):
|
||||
if len(bits) != 1:
|
||||
raise IDInternal.DoesNotExist
|
||||
rfc = re.match('rfc(\d+)', bits[0])
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
return IDInternal.objects.get(docalias__name=bits[0])
|
||||
|
||||
if rfc:
|
||||
return IDInternal.objects.get(draft=int(rfc.group(1)), rfc_flag=1)
|
||||
else:
|
||||
return IDInternal.objects.get(draft__filename=bits[0], rfc_flag=0)
|
||||
|
||||
def title(self, obj):
|
||||
# filename is a function for RFCs and an attribute for I-Ds.
|
||||
# This works transparently for templates but is not transparent
|
||||
# for python.
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
return "I-D Tracker comments for %s" % obj.filename
|
||||
|
||||
if obj.rfc_flag:
|
||||
filename = obj.document().filename()
|
||||
else:
|
||||
filename = obj.document().filename
|
||||
return "I-D Tracker comments for %s" % filename
|
||||
|
||||
def link(self, obj):
|
||||
if obj is None:
|
||||
raise FeedDoesNotExist
|
||||
return obj.get_absolute_url()
|
||||
|
||||
def description(self, obj):
|
||||
return self.title(obj)
|
||||
|
||||
def items(self, obj):
|
||||
return obj.public_comments().order_by("-date","-id")
|
||||
|
||||
def item_pubdate(self, item):
|
||||
return item.datetime()
|
||||
|
||||
def item_author_name(self, item):
|
||||
return item.get_author()
|
||||
|
||||
class InLastCall(Feed):
|
||||
title = "Documents in Last Call"
|
||||
feed_type = Atom1Feed
|
||||
author_name = 'IESG Secretary'
|
||||
link = "/idtracker/status/last-call/"
|
||||
|
||||
def items(self):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
ret = list(IDInternal.objects.filter(states__type="draft-iesg", states__slug="lc"))
|
||||
else:
|
||||
ret = list(IDInternal.objects.filter(primary_flag=1).filter(cur_state__state='In Last Call'))
|
||||
ret.sort(key=lambda item: (item.document().lc_expiration_date or datetime.date.today()))
|
||||
return ret
|
||||
|
||||
def item_pubdate(self, item):
|
||||
# this method needs to return a datetime instance, even
|
||||
# though the database has only date, not time
|
||||
return datetime.datetime.combine((item.document().lc_sent_date or datetime.datetime.now().date()), datetime.time(0,0,0))
|
||||
|
1
ietf/idtracker/fixtures/.gitignore
vendored
1
ietf/idtracker/fixtures/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/*.pyc
|
|
@ -1,151 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<django-objects version="1.0">
|
||||
<object pk="4" model="idtracker.personororginfo">
|
||||
<field type="CharField" name="record_type"></field>
|
||||
<field type="CharField" name="name_prefix"></field>
|
||||
<field type="CharField" name="first_name">Hermey</field>
|
||||
<field type="CharField" name="first_name_key">HERMEY</field>
|
||||
<field type="CharField" name="middle_initial"></field>
|
||||
<field type="CharField" name="middle_initial_key"></field>
|
||||
<field type="CharField" name="last_name">Elf</field>
|
||||
<field type="CharField" name="last_name_key">ELF</field>
|
||||
<field type="CharField" name="name_suffix"></field>
|
||||
<field type="DateField" name="date_modified">2007-07-02</field>
|
||||
<field type="CharField" name="modified_by"></field>
|
||||
<field type="DateField" name="date_created">2007-07-02</field>
|
||||
<field type="CharField" name="created_by"></field>
|
||||
<field type="CharField" name="address_type"></field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.personororginfo">
|
||||
<field type="CharField" name="record_type"></field>
|
||||
<field type="CharField" name="name_prefix"></field>
|
||||
<field type="CharField" name="first_name">Kris</field>
|
||||
<field type="CharField" name="first_name_key">KRIS</field>
|
||||
<field type="CharField" name="middle_initial"></field>
|
||||
<field type="CharField" name="middle_initial_key"></field>
|
||||
<field type="CharField" name="last_name">Kringle</field>
|
||||
<field type="CharField" name="last_name_key">KRINGLE</field>
|
||||
<field type="CharField" name="name_suffix"></field>
|
||||
<field type="DateField" name="date_modified">2007-07-02</field>
|
||||
<field type="CharField" name="modified_by"></field>
|
||||
<field type="DateField" name="date_created">2007-07-02</field>
|
||||
<field type="CharField" name="created_by"></field>
|
||||
<field type="CharField" name="address_type"></field>
|
||||
</object>
|
||||
<object pk="2" model="idtracker.personororginfo">
|
||||
<field type="CharField" name="record_type"></field>
|
||||
<field type="CharField" name="name_prefix"></field>
|
||||
<field type="CharField" name="first_name">Snow</field>
|
||||
<field type="CharField" name="first_name_key">SNOW</field>
|
||||
<field type="CharField" name="middle_initial"></field>
|
||||
<field type="CharField" name="middle_initial_key"></field>
|
||||
<field type="CharField" name="last_name">Miser</field>
|
||||
<field type="CharField" name="last_name_key">MISER</field>
|
||||
<field type="CharField" name="name_suffix"></field>
|
||||
<field type="DateField" name="date_modified">2007-07-02</field>
|
||||
<field type="CharField" name="modified_by"></field>
|
||||
<field type="DateField" name="date_created">2007-07-02</field>
|
||||
<field type="CharField" name="created_by"></field>
|
||||
<field type="CharField" name="address_type"></field>
|
||||
</object>
|
||||
<object pk="3" model="idtracker.personororginfo">
|
||||
<field type="CharField" name="record_type"></field>
|
||||
<field type="CharField" name="name_prefix"></field>
|
||||
<field type="CharField" name="first_name">Rudolph</field>
|
||||
<field type="CharField" name="first_name_key">RUDOLPH</field>
|
||||
<field type="CharField" name="middle_initial"></field>
|
||||
<field type="CharField" name="middle_initial_key"></field>
|
||||
<field type="CharField" name="last_name">Reindeer</field>
|
||||
<field type="CharField" name="last_name_key">REINDEER</field>
|
||||
<field type="CharField" name="name_suffix"></field>
|
||||
<field type="DateField" name="date_modified">2007-07-02</field>
|
||||
<field type="CharField" name="modified_by"></field>
|
||||
<field type="DateField" name="date_created">2007-07-02</field>
|
||||
<field type="CharField" name="created_by"></field>
|
||||
<field type="CharField" name="address_type"></field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.wgchair">
|
||||
<field to="idtracker.personororginfo" name="person" rel="ManyToOneRel">1</field>
|
||||
<field to="idtracker.ietfwg" name="group_acronym" rel="ManyToOneRel">1</field>
|
||||
</object>
|
||||
<object pk="2" model="idtracker.wgchair">
|
||||
<field to="idtracker.personororginfo" name="person" rel="ManyToOneRel">2</field>
|
||||
<field to="idtracker.ietfwg" name="group_acronym" rel="ManyToOneRel">2</field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.ietfwg">
|
||||
<field to="idtracker.wgtype" name="group_type" rel="ManyToOneRel">1</field>
|
||||
<field type="DateField" name="proposed_date"><None></None></field>
|
||||
<field type="DateField" name="start_date"><None></None></field>
|
||||
<field type="DateField" name="dormant_date"><None></None></field>
|
||||
<field type="DateField" name="concluded_date"><None></None></field>
|
||||
<field to="idtracker.wgstatus" name="status" rel="ManyToOneRel">1</field>
|
||||
<field to="idtracker.areadirector" name="area_director" rel="ManyToOneRel"><None></None></field>
|
||||
<field type="CharField" name="meeting_scheduled"></field>
|
||||
<field type="CharField" name="email_address"></field>
|
||||
<field type="CharField" name="email_subscribe"></field>
|
||||
<field type="CharField" name="email_keyword"></field>
|
||||
<field type="CharField" name="email_archive"></field>
|
||||
<field type="TextField" name="comments"></field>
|
||||
<field type="DateField" name="last_modified_date">2007-07-02</field>
|
||||
<field type="CharField" name="meeting_scheduled_old"></field>
|
||||
</object>
|
||||
<object pk="2" model="idtracker.ietfwg">
|
||||
<field to="idtracker.wgtype" name="group_type" rel="ManyToOneRel">3</field>
|
||||
<field type="DateField" name="proposed_date"><None></None></field>
|
||||
<field type="DateField" name="start_date"><None></None></field>
|
||||
<field type="DateField" name="dormant_date"><None></None></field>
|
||||
<field type="DateField" name="concluded_date"><None></None></field>
|
||||
<field to="idtracker.wgstatus" name="status" rel="ManyToOneRel">1</field>
|
||||
<field to="idtracker.areadirector" name="area_director" rel="ManyToOneRel"><None></None></field>
|
||||
<field type="CharField" name="meeting_scheduled"></field>
|
||||
<field type="CharField" name="email_address"></field>
|
||||
<field type="CharField" name="email_subscribe"></field>
|
||||
<field type="CharField" name="email_keyword"></field>
|
||||
<field type="CharField" name="email_archive"></field>
|
||||
<field type="TextField" name="comments"></field>
|
||||
<field type="DateField" name="last_modified_date">2007-07-02</field>
|
||||
<field type="CharField" name="meeting_scheduled_old"></field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.acronym">
|
||||
<field type="CharField" name="acronym">xmas</field>
|
||||
<field type="CharField" name="name">Christmas</field>
|
||||
<field type="CharField" name="name_key">CHRISTMAS</field>
|
||||
</object>
|
||||
<object pk="2" model="idtracker.acronym">
|
||||
<field type="CharField" name="acronym">snow</field>
|
||||
<field type="CharField" name="name">Silly New Operational Work</field>
|
||||
<field type="CharField" name="name_key">SILLY NEW OPERATIONAL WORK</field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.wgtype">
|
||||
<field type="CharField" name="type">WG</field>
|
||||
</object>
|
||||
<object pk="2" model="idtracker.wgtype">
|
||||
<field type="CharField" name="type">PWG</field>
|
||||
</object>
|
||||
<object pk="3" model="idtracker.wgtype">
|
||||
<field type="CharField" name="type">BOF</field>
|
||||
</object>
|
||||
<object pk="4" model="idtracker.wgtype">
|
||||
<field type="CharField" name="type">AG</field>
|
||||
</object>
|
||||
<object pk="5" model="idtracker.wgtype">
|
||||
<field type="CharField" name="type">TEAM</field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.wgstatus">
|
||||
<field type="CharField" name="status">Active</field>
|
||||
</object>
|
||||
<object pk="2" model="idtracker.wgstatus">
|
||||
<field type="CharField" name="status">Dormant</field>
|
||||
</object>
|
||||
<object pk="3" model="idtracker.wgstatus">
|
||||
<field type="CharField" name="status">Concluded</field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.wgtechadvisor">
|
||||
<field to="idtracker.ietfwg" name="group_acronym" rel="ManyToOneRel">1</field>
|
||||
<field to="idtracker.personororginfo" name="person" rel="ManyToOneRel">3</field>
|
||||
</object>
|
||||
<object pk="1" model="idtracker.wgsecretary">
|
||||
<field to="idtracker.ietfwg" name="group_acronym" rel="ManyToOneRel">1</field>
|
||||
<field to="idtracker.personororginfo" name="person" rel="ManyToOneRel">4</field>
|
||||
</object>
|
||||
</django-objects>
|
|
@ -1,22 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
#
|
||||
from django.contrib.sitemaps import Sitemap
|
||||
from django.conf import settings
|
||||
from ietf.idtracker.models import IDInternal, InternetDraft
|
||||
|
||||
class IDTrackerMap(Sitemap):
|
||||
changefreq = "always"
|
||||
def items(self):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
return IDInternal.objects.all()
|
||||
else:
|
||||
return IDInternal.objects.exclude(draft=999999)
|
||||
|
||||
class DraftMap(Sitemap):
|
||||
changefreq = "always"
|
||||
def items(self):
|
||||
return InternetDraft.objects.all()
|
||||
def location(self, obj):
|
||||
return "/drafts/%s/" % obj.filename
|
||||
def lastmod(self, obj):
|
||||
return obj.last_modified_date
|
|
@ -31,9 +31,18 @@ def expand_comma(value):
|
|||
def format_charter(value):
|
||||
return value.replace("\n\n", "</p><p>").replace("\n","<br/>\n")
|
||||
|
||||
@register.filter(name='indent')
|
||||
def indent(value,numspaces=2):
|
||||
return value.replace("\n", "\n"+" "*int(numspaces));
|
||||
@register.filter
|
||||
def indent(value, numspaces=2):
|
||||
replacement = "\n" + " " * int(numspaces)
|
||||
res = value.replace("\n", replacement)
|
||||
if res.endswith(replacement):
|
||||
res = res[:-int(numspaces)] # fix up superfluous spaces
|
||||
return res
|
||||
|
||||
@register.filter
|
||||
def unindent(value):
|
||||
"""Remove indentation from string."""
|
||||
return re.sub("\n +", "\n", value)
|
||||
|
||||
@register.filter(name='parse_email_list')
|
||||
def parse_email_list(value):
|
||||
|
@ -241,6 +250,11 @@ def dashify(string):
|
|||
"""
|
||||
return re.sub('.', '-', string)
|
||||
|
||||
@register.filter
|
||||
def underline(string):
|
||||
"""Return string with an extra line underneath of dashes, for plain text underlining."""
|
||||
return string + "\n" + ("-" * len(string))
|
||||
|
||||
@register.filter(name='lstrip')
|
||||
def lstripw(string, chars):
|
||||
"""Strip matching leading characters from words in string"""
|
||||
|
@ -320,23 +334,6 @@ def wrap_text(text, width=72):
|
|||
prev_indent = indent
|
||||
return "\n".join(filled)
|
||||
|
||||
@register.filter(name="id_index_file_types")
|
||||
def id_index_file_types(text):
|
||||
r = ".txt"
|
||||
if text.find("txt") < 0:
|
||||
return r
|
||||
if text.find("ps") >= 0:
|
||||
r = r + ",.ps"
|
||||
if text.find("pdf") >= 0:
|
||||
r = r + ",.pdf"
|
||||
return r
|
||||
|
||||
@register.filter(name="id_index_wrap")
|
||||
def id_index_wrap(text):
|
||||
x = wordwrap(text, 72)
|
||||
x = x.replace("\n", "\n ")
|
||||
return " "+x.strip()
|
||||
|
||||
@register.filter(name="compress_empty_lines")
|
||||
def compress_empty_lines(text):
|
||||
text = re.sub("( *\n){3,}", "\n\n", text)
|
||||
|
@ -408,14 +405,6 @@ def expires_soon(x,request):
|
|||
days = 14
|
||||
return x > -days
|
||||
|
||||
@register.filter(name='greater_than')
|
||||
def greater_than(x, y):
|
||||
return x > int(y)
|
||||
|
||||
@register.filter(name='less_than')
|
||||
def less_than(x, y):
|
||||
return x < int(y)
|
||||
|
||||
@register.filter(name='equal')
|
||||
def equal(x, y):
|
||||
return str(x)==str(y)
|
||||
|
@ -470,32 +459,22 @@ def format_history_text(text):
|
|||
full = mark_safe(keep_spacing(linebreaksbr(urlize(sanitize_html(full)))))
|
||||
snippet = truncate_html_words(full, 25)
|
||||
if snippet != full:
|
||||
return mark_safe(u'<div class="snippet">%s<span class="showAll">[show all]</span></div><div style="display:none" class="full">%s</div>' % (snippet, full))
|
||||
return mark_safe(u'<div class="snippet">%s<span class="show-all">[show all]</span></div><div style="display:none" class="full">%s</div>' % (snippet, full))
|
||||
return full
|
||||
|
||||
@register.filter
|
||||
def user_roles_json(user):
|
||||
roles = {}
|
||||
if not isinstance(user, basestring) and user.is_authenticated():
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.group.models import Role
|
||||
for r in Role.objects.filter(person__user=user).select_related(depth=1):
|
||||
if r.name_id == "secr" and r.group.acronym == "secretariat":
|
||||
roles["Secretariat"] = True
|
||||
elif r.name_id == "ad" and r.group.type_id == "area" and r.group.state_id == "active":
|
||||
roles["Area Director"] = roles["Area_Director"] = True
|
||||
else:
|
||||
for g in user.groups.all():
|
||||
roles[g.name] = True
|
||||
return mark_safe(simplejson.dumps(roles))
|
||||
|
||||
@register.filter
|
||||
def textify(text):
|
||||
text = re.sub("</?b>", "*", text)
|
||||
text = re.sub("</?i>", "/", text)
|
||||
# There are probably additional conversions we should apply here
|
||||
return text
|
||||
|
||||
|
||||
@register.filter
|
||||
def state(doc, slug):
|
||||
if slug == "stream": # convenient shorthand
|
||||
slug = "%s-stream-%s" % (doc.type_id, doc.stream_id)
|
||||
return doc.get_state(slug)
|
||||
|
||||
def _test():
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django import template
|
||||
from ietf import __date__, __rev__, __version__, __id__
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def revision_time():
|
||||
return __date__[7:32]
|
||||
|
||||
@register.simple_tag
|
||||
def revision_date():
|
||||
return __date__[34:-3]
|
||||
|
||||
@register.simple_tag
|
||||
def revision_num():
|
||||
return __rev__[6:-2]
|
||||
|
||||
@register.simple_tag
|
||||
def revision_id():
|
||||
return __id__[5:-2]
|
||||
|
||||
@register.simple_tag
|
||||
def version_num():
|
||||
return __version__
|
||||
|
|
@ -1,42 +1,10 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
#
|
||||
import doctest
|
||||
import doctest, unittest
|
||||
|
||||
from ietf.idtracker.templatetags import ietf_filters
|
||||
import unittest
|
||||
from ietf.utils.test_utils import SimpleUrlTestCase, canonicalize_feed, canonicalize_sitemap
|
||||
import django.test
|
||||
|
||||
class TemplateTagTest(unittest.TestCase):
|
||||
def testTemplateTags(self):
|
||||
print " Testing ietf_filters"
|
||||
#doctest.testmod(ietf_filters,verbose=True)
|
||||
(failures, tests) = doctest.testmod(ietf_filters)
|
||||
def test_template_tags(self):
|
||||
failures, tests = doctest.testmod(ietf_filters)
|
||||
self.assertEqual(failures, 0)
|
||||
print "OK (ietf_filters)"
|
||||
|
||||
class IdTrackerUrlTestCase(SimpleUrlTestCase):
|
||||
def testUrls(self):
|
||||
self.doTestUrls(__file__)
|
||||
def doCanonicalize(self, url, content):
|
||||
if url.startswith("/feed/"):
|
||||
return canonicalize_feed(content)
|
||||
elif url.startswith("/sitemap"):
|
||||
return canonicalize_sitemap(content)
|
||||
else:
|
||||
return content
|
||||
|
||||
# class WGRoleTest(django.test.TestCase):
|
||||
# fixtures = ['wgtest']
|
||||
#
|
||||
# def setUp(self):
|
||||
# from ietf.idtracker.models import IETFWG
|
||||
# self.xmas = IETFWG.objects.get(group_acronym__acronym='xmas')
|
||||
# self.snow = IETFWG.objects.get(group_acronym__acronym='snow')
|
||||
#
|
||||
# def test_roles(self):
|
||||
# print " Testing WG roles"
|
||||
# self.assertEquals(self.xmas.wgchair_set.all()[0].role(), 'xmas WG Chair')
|
||||
# self.assertEquals(self.snow.wgchair_set.all()[0].role(), 'snow BOF Chair')
|
||||
# self.assertEquals(self.xmas.wgsecretary_set.all()[0].role(), 'xmas WG Secretary')
|
||||
# self.assertEquals(self.xmas.wgtechadvisor_set.all()[0].role(), 'xmas Technical Advisor')
|
||||
# print "OK"
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
200 /idtracker/help/state/
|
||||
200 /idtracker/help/state/12/
|
||||
200 /idtracker/help/substate/1/
|
||||
301 /idtracker/help/evaluation/
|
||||
200 /idtracker/status/
|
||||
200 /idtracker/status/last-call/
|
||||
|
||||
301 /idtracker/rfc3847/
|
||||
301 /idtracker/draft-ietf-isis-link-attr/
|
||||
301 /idtracker/draft-eronen-tls-psk/ # no IESG information
|
||||
301 /idtracker/
|
||||
200 /feed/comments/draft-ietf-isis-link-attr/
|
||||
200 /feed/comments/rfc3373/
|
||||
200 /feed/last-call/
|
||||
|
||||
# An RFC with no matching value in InternetDrafts. This tests
|
||||
# subtle cases of using the draft relation when it's not appropriate.
|
||||
# See ticket #218.
|
||||
301 /idtracker/rfc2444/
|
||||
200 /feed/comments/rfc2444/
|
||||
|
||||
# Test case for missing comment time (bug fixed in changeset 1733)
|
||||
200 /feed/comments/draft-ietf-msec-newtype-keyid/
|
||||
|
||||
#200,heavy /sitemap-idtracker.xml
|
|
@ -1,26 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
from ietf.idtracker.models import IDState, IDSubState
|
||||
from ietf.idtracker import views
|
||||
from django.views.generic.simple import redirect_to
|
||||
|
||||
urlpatterns = patterns('django.views.generic.simple',
|
||||
url(r'^help/state/$', 'direct_to_template', { 'template': 'idtracker/states.html', 'extra_context': { 'states': IDState.objects.all(), 'substates': IDSubState.objects.all() } }, name="help_states"),
|
||||
(r'^help/evaluation/$', redirect_to, {'url':'http://www.ietf.org/iesg/voting-procedures.html' }),
|
||||
)
|
||||
urlpatterns += patterns('',
|
||||
(r'^status/$', views.status),
|
||||
(r'^status/last-call/$', views.last_call),
|
||||
)
|
||||
urlpatterns += patterns('',
|
||||
(r'^rfc0*(?P<rfc_number>\d+)/$', views.redirect_rfc),
|
||||
(r'^(?P<object_id>\d+)/$', views.redirect_id),
|
||||
(r'^(?P<filename>[^/]+)/$', views.redirect_filename),
|
||||
(r'^comment/(?P<object_id>\d+)/$', views.redirect_comment),
|
||||
(r'^ballot/(?P<object_id>\d+)/$', views.redirect_ballot),
|
||||
(r'^([^/]+)/comment/(?P<object_id>\d+)/$', views.redirect_comment),
|
||||
(r'^help/state/(?P<state>\d+)/$', views.state_desc),
|
||||
(r'^help/substate/(?P<state>\d+)/$', views.state_desc, { 'is_substate': 1 }),
|
||||
(r'^$', redirect_to, { 'url': '/doc/'}),
|
||||
)
|
|
@ -1,89 +0,0 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
# Create your views here.
|
||||
from django.http import HttpResponsePermanentRedirect, Http404
|
||||
from django.conf import settings
|
||||
from django.template import RequestContext
|
||||
from django.shortcuts import get_object_or_404, render_to_response
|
||||
from django.views.generic.list_detail import object_detail, object_list
|
||||
from ietf.idtracker.models import InternetDraft, IDInternal, IDState, IDSubState, BallotInfo, DocumentComment
|
||||
import re, datetime
|
||||
|
||||
def state_desc(request, state, is_substate=0):
|
||||
if int(state) == 100:
|
||||
object = {
|
||||
'state': 'I-D Exists',
|
||||
'description': """
|
||||
Initial (default) state for all internet drafts. Such documents are
|
||||
not being tracked by the IESG as no request has been made of the
|
||||
IESG to do anything with the document.
|
||||
"""
|
||||
}
|
||||
elif is_substate:
|
||||
sub = get_object_or_404(IDSubState, pk=state)
|
||||
object = { 'state': sub.sub_state, 'description': sub.description }
|
||||
else:
|
||||
object = get_object_or_404(IDState, pk=state)
|
||||
return render_to_response('idtracker/state_desc.html', {'state': object},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def status(request):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
drafts = IDInternal.objects.filter(states__type="draft-iesg").exclude(states__type="draft-iesg", states__slug__in=('pub', 'dead', 'watching', 'rfcqueue')).distinct().order_by('states__order')
|
||||
drafts = [ d for d in drafts if not d.replaced_by ]
|
||||
drafts.sort(key=lambda d: (d.cur_state_id, d.status_date or datetime.date.min, d.b_sent_date or datetime.date.min))
|
||||
# sadly we can't use the generic view because it only works with a queryset...
|
||||
return render_to_response('idtracker/status_of_items.html', dict(object_list=drafts, title="IESG Status of Items"), context_instance=RequestContext(request))
|
||||
|
||||
queryset = IDInternal.objects.filter(primary_flag=1).exclude(cur_state__state__in=('RFC Ed Queue', 'RFC Published', 'AD is watching', 'Dead')).order_by('cur_state', 'status_date', 'ballot')
|
||||
return object_list(request, template_name="idtracker/status_of_items.html", queryset=queryset, extra_context={'title': 'IESG Status of Items'})
|
||||
|
||||
def last_call(request):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
drafts = list(IDInternal.objects.filter(states__type="draft-iesg", states__slug__in=('lc', 'writeupw', 'goaheadw')).distinct().order_by('states__order'))
|
||||
drafts.sort(key=lambda d: (d.cur_state_id, d.status_date or datetime.date.min, d.b_sent_date or datetime.date.min))
|
||||
# sadly we can't use the generic view because it only works with a queryset...
|
||||
return render_to_response('idtracker/status_of_items.html', dict(object_list=drafts, title="Documents in Last Call", lastcall=1), context_instance=RequestContext(request))
|
||||
|
||||
queryset = IDInternal.objects.filter(primary_flag=1).filter(cur_state__state__in=('In Last Call', 'Waiting for Writeup', 'Waiting for AD Go-Ahead')).order_by('cur_state', 'status_date', 'ballot')
|
||||
return object_list(request, template_name="idtracker/status_of_items.html", queryset=queryset, extra_context={'title': 'Documents in Last Call', 'lastcall': 1})
|
||||
|
||||
def redirect_id(request, object_id):
|
||||
'''Redirect from historical document ID to preferred filename url.'''
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
raise Http404() # we don't store the numbers anymore
|
||||
|
||||
doc = get_object_or_404(InternetDraft, id_document_tag=object_id)
|
||||
return HttpResponsePermanentRedirect("/doc/"+doc.filename+"/")
|
||||
|
||||
def redirect_rfc(request, rfc_number):
|
||||
return HttpResponsePermanentRedirect("/doc/rfc"+rfc_number+"/")
|
||||
|
||||
def redirect_filename(request, filename):
|
||||
return HttpResponsePermanentRedirect("/doc/"+filename+"/")
|
||||
|
||||
def redirect_ballot(request, object_id):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
raise Http404() # we don't store the numbers anymore
|
||||
|
||||
ballot = get_object_or_404(BallotInfo, pk=object_id)
|
||||
ids = ballot.drafts.filter(primary_flag=1)
|
||||
if len(ids) == 0:
|
||||
raise Http404("Ballot does not correspond to any document")
|
||||
id = ids[0]
|
||||
if id.rfc_flag:
|
||||
return HttpResponsePermanentRedirect("/doc/rfc"+str(id.draft_id)+"/#ballot")
|
||||
else:
|
||||
return HttpResponsePermanentRedirect("/doc/"+id.draft.filename+"/#ballot")
|
||||
|
||||
def redirect_comment(request, object_id):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
raise Http404() # we don't store the numbers anymore
|
||||
|
||||
comment = get_object_or_404(DocumentComment, pk=object_id)
|
||||
id = comment.document
|
||||
if id.rfc_flag:
|
||||
return HttpResponsePermanentRedirect("/doc/rfc"+str(id.draft_id)+"/#history-"+str(object_id))
|
||||
else:
|
||||
return HttpResponsePermanentRedirect("/doc/"+id.draft.filename+"/#history-"+str(object_id))
|
||||
|
|
@ -505,11 +505,11 @@ class DeferUndeferTestCase(django.test.TestCase):
|
|||
self.assertEquals(len(q('form.defer')),1)
|
||||
|
||||
# defer
|
||||
self.assertEquals(doc.telechat_date,first_date)
|
||||
self.assertEquals(doc.telechat_date(), first_date)
|
||||
r = self.client.post(url,dict())
|
||||
self.assertEquals(r.status_code, 302)
|
||||
doc = Document.objects.get(name=name)
|
||||
self.assertEquals(doc.telechat_date,second_date)
|
||||
self.assertEquals(doc.telechat_date(), second_date)
|
||||
self.assertTrue(doc.returning_item())
|
||||
defer_states = dict(draft=['draft-iesg','defer'],conflrev=['conflrev','defer'])
|
||||
if doc.type_id in defer_states:
|
||||
|
@ -547,11 +547,11 @@ class DeferUndeferTestCase(django.test.TestCase):
|
|||
self.assertEquals(len(q('form.undefer')),1)
|
||||
|
||||
# undefer
|
||||
self.assertEquals(doc.telechat_date,second_date)
|
||||
self.assertEquals(doc.telechat_date(), second_date)
|
||||
r = self.client.post(url,dict())
|
||||
self.assertEquals(r.status_code, 302)
|
||||
doc = Document.objects.get(name=name)
|
||||
self.assertEquals(doc.telechat_date,first_date)
|
||||
self.assertEquals(doc.telechat_date(), first_date)
|
||||
self.assertTrue(doc.returning_item())
|
||||
undefer_states = dict(draft=['draft-iesg','iesg-eva'],conflrev=['conflrev','iesgeval'])
|
||||
if doc.type_id in undefer_states:
|
||||
|
|
|
@ -515,8 +515,7 @@ class RescheduleForm(forms.Form):
|
|||
self.fields['telechat_date'].choices = choices
|
||||
|
||||
def handle_reschedule_form(request, doc, dates):
|
||||
initial = dict(
|
||||
telechat_date=doc.telechat_date if doc.on_upcoming_agenda() else None)
|
||||
initial = dict(telechat_date=doc.telechat_date())
|
||||
|
||||
formargs = dict(telechat_dates=dates,
|
||||
prefix="%s" % doc.name,
|
||||
|
@ -551,11 +550,11 @@ def agenda_documents(request):
|
|||
i.reschedule_form = handle_reschedule_form(request, i, dates)
|
||||
|
||||
# some may have been taken off the schedule by the reschedule form
|
||||
docs = filter(lambda x: x.on_upcoming_agenda(), docs)
|
||||
|
||||
docs = [d for d in docs if d.telechat_date()]
|
||||
|
||||
telechats = []
|
||||
for date in dates:
|
||||
matches = filter(lambda x: x.telechat_date == date, docs)
|
||||
matches = filter(lambda x: x.telechat_date() == date, docs)
|
||||
res = {}
|
||||
for i in matches:
|
||||
section_key = "s" + get_doc_section(i)
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
#from django import newforms as forms
|
||||
from ietf.idtracker.views import InternetDraft
|
||||
from ietf.idtracker.models import Rfc
|
||||
from ietf.utils.lazy import reverse_lazy
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
@ -139,9 +136,6 @@ class IprDetail(models.Model):
|
|||
return None
|
||||
except IprContact.MultipleObjectsReturned:
|
||||
return self.contact.filter(contact_type=3)[0]
|
||||
class Meta:
|
||||
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
db_table = 'ipr_detail'
|
||||
|
||||
class IprContact(models.Model):
|
||||
TYPE_CHOICES = (
|
||||
|
@ -162,20 +156,8 @@ class IprContact(models.Model):
|
|||
email = models.EmailField(max_length=255)
|
||||
def __str__(self):
|
||||
return self.name or '<no name>'
|
||||
class Meta:
|
||||
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
db_table = 'ipr_contacts'
|
||||
|
||||
|
||||
class IprDraft(models.Model):
|
||||
ipr = models.ForeignKey(IprDetail, related_name='drafts_old' if settings.USE_DB_REDESIGN_PROXY_CLASSES else 'drafts')
|
||||
document = models.ForeignKey(InternetDraft, db_column='id_document_tag', related_name="ipr_draft_old" if settings.USE_DB_REDESIGN_PROXY_CLASSES else "ipr")
|
||||
revision = models.CharField(max_length=2)
|
||||
def __str__(self):
|
||||
return "%s which applies to %s-%s" % ( self.ipr, self.document, self.revision )
|
||||
class Meta:
|
||||
db_table = 'ipr_ids'
|
||||
|
||||
class IprNotification(models.Model):
|
||||
ipr = models.ForeignKey(IprDetail)
|
||||
notification = models.TextField(blank=True)
|
||||
|
@ -183,94 +165,70 @@ class IprNotification(models.Model):
|
|||
time_sent = models.CharField(blank=True, max_length=25)
|
||||
def __str__(self):
|
||||
return "IPR notification for %s sent %s %s" % (self.ipr, self.date_sent, self.time_sent)
|
||||
class Meta:
|
||||
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
db_table = 'ipr_notifications'
|
||||
|
||||
class IprRfc(models.Model):
|
||||
ipr = models.ForeignKey(IprDetail, related_name='rfcs_old' if settings.USE_DB_REDESIGN_PROXY_CLASSES else 'rfcs')
|
||||
document = models.ForeignKey(Rfc, db_column='rfc_number', related_name="ipr_rfc_old" if settings.USE_DB_REDESIGN_PROXY_CLASSES else "ipr")
|
||||
def __str__(self):
|
||||
return "%s applies to RFC%04d" % ( self.ipr, self.document_id )
|
||||
class Meta:
|
||||
db_table = 'ipr_rfcs'
|
||||
|
||||
class IprUpdate(models.Model):
|
||||
ipr = models.ForeignKey(IprDetail, related_name='updates')
|
||||
updated = models.ForeignKey(IprDetail, db_column='updated', related_name='updated_by')
|
||||
status_to_be = models.IntegerField(null=True, blank=True)
|
||||
processed = models.IntegerField(null=True, blank=True)
|
||||
|
||||
|
||||
from ietf.doc.models import DocAlias
|
||||
|
||||
class IprDocAlias(models.Model):
|
||||
ipr = models.ForeignKey(IprDetail, related_name='documents')
|
||||
doc_alias = models.ForeignKey(DocAlias)
|
||||
rev = models.CharField(max_length=2, blank=True)
|
||||
def __unicode__(self):
|
||||
if self.rev:
|
||||
return u"%s which applies to %s-%s" % (self.ipr, self.doc_alias.name, self.rev)
|
||||
else:
|
||||
return u"%s which applies to %s" % (self.ipr, self.doc_alias.name)
|
||||
|
||||
class Meta:
|
||||
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
db_table = 'ipr_updates'
|
||||
verbose_name = "IPR document alias"
|
||||
verbose_name_plural = "IPR document aliases"
|
||||
|
||||
# proxy stuff
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES or hasattr(settings, "IMPORTING_IPR"):
|
||||
from ietf.doc.models import DocAlias
|
||||
|
||||
class IprDocAlias(models.Model):
|
||||
ipr = models.ForeignKey(IprDetail, related_name='documents')
|
||||
doc_alias = models.ForeignKey(DocAlias)
|
||||
rev = models.CharField(max_length=2, blank=True)
|
||||
def __unicode__(self):
|
||||
if self.rev:
|
||||
return u"%s which applies to %s-%s" % (self.ipr, self.doc_alias.name, self.rev)
|
||||
else:
|
||||
return u"%s which applies to %s" % (self.ipr, self.doc_alias.name)
|
||||
from ietf.utils.proxy import TranslatingManager
|
||||
|
||||
class Meta:
|
||||
verbose_name = "IPR document alias"
|
||||
verbose_name_plural = "IPR document aliases"
|
||||
class IprDraftProxy(IprDocAlias):
|
||||
objects = TranslatingManager(dict(document="doc_alias__name"))
|
||||
|
||||
# proxy stuff
|
||||
IprDraftOld = IprDraft
|
||||
IprRfcOld = IprRfc
|
||||
# document = models.ForeignKey(InternetDraft, db_column='id_document_tag', "ipr")
|
||||
# document = models.ForeignKey(Rfc, db_column='rfc_number', related_name="ipr")
|
||||
@property
|
||||
def document(self):
|
||||
from ietf.doc.proxy import DraftLikeDocAlias
|
||||
return DraftLikeDocAlias.objects.get(pk=self.doc_alias_id)
|
||||
|
||||
from ietf.utils.proxy import TranslatingManager
|
||||
|
||||
class IprDraftProxy(IprDocAlias):
|
||||
objects = TranslatingManager(dict(document="doc_alias__name"))
|
||||
|
||||
# document = models.ForeignKey(InternetDraft, db_column='id_document_tag', "ipr")
|
||||
# document = models.ForeignKey(Rfc, db_column='rfc_number', related_name="ipr")
|
||||
@property
|
||||
def document(self):
|
||||
from ietf.doc.proxy import DraftLikeDocAlias
|
||||
return DraftLikeDocAlias.objects.get(pk=self.doc_alias_id)
|
||||
|
||||
#revision = models.CharField(max_length=2)
|
||||
@property
|
||||
def revision(self):
|
||||
return self.rev
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
#revision = models.CharField(max_length=2)
|
||||
@property
|
||||
def revision(self):
|
||||
return self.rev
|
||||
|
||||
IprDraft = IprDraftProxy
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
class IprRfcProxy(IprDocAlias):
|
||||
objects = TranslatingManager(dict(document=lambda v: ("doc_alias__name", "rfc%s" % v)))
|
||||
|
||||
# document = models.ForeignKey(InternetDraft, db_column='id_document_tag', "ipr")
|
||||
# document = models.ForeignKey(Rfc, db_column='rfc_number', related_name="ipr")
|
||||
@property
|
||||
def document(self):
|
||||
from ietf.doc.proxy import DraftLikeDocAlias
|
||||
return DraftLikeDocAlias.objects.get(pk=self.doc_alias_id)
|
||||
|
||||
#revision = models.CharField(max_length=2)
|
||||
@property
|
||||
def revision(self):
|
||||
return self.rev
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
IprDraft = IprDraftProxy
|
||||
|
||||
IprRfc = IprRfcProxy
|
||||
|
||||
class IprRfcProxy(IprDocAlias):
|
||||
objects = TranslatingManager(dict(document=lambda v: ("doc_alias__name", "rfc%s" % v)))
|
||||
|
||||
# document = models.ForeignKey(InternetDraft, db_column='id_document_tag', "ipr")
|
||||
# document = models.ForeignKey(Rfc, db_column='rfc_number', related_name="ipr")
|
||||
@property
|
||||
def document(self):
|
||||
from ietf.doc.proxy import DraftLikeDocAlias
|
||||
return DraftLikeDocAlias.objects.get(pk=self.doc_alias_id)
|
||||
|
||||
# changes done by convert-096.py:changed maxlength to max_length
|
||||
# removed core
|
||||
# removed edit_inline
|
||||
# removed raw_id_admin
|
||||
#revision = models.CharField(max_length=2)
|
||||
@property
|
||||
def revision(self):
|
||||
return self.rev
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
IprRfc = IprRfcProxy
|
||||
|
|
|
@ -15,7 +15,7 @@ urlpatterns = patterns('',
|
|||
(r'^new-(?P<type>specific)/$', new.new),
|
||||
(r'^new-(?P<type>generic)/$', new.new),
|
||||
(r'^new-(?P<type>third-party)/$', new.new),
|
||||
(r'^search/$', search.search),
|
||||
url(r'^search/$', search.search, name="ipr_search"),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -45,10 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% block morecss %}{% endblock %}
|
||||
</style>
|
||||
{% block pagehead %}{% endblock %}
|
||||
<script type="text/javascript">
|
||||
IETF = {};
|
||||
IETF.user_groups = {{ user|user_roles_json }};
|
||||
</script>
|
||||
{% ifnotequal server_mode "production" %}
|
||||
<link rel="icon" href="/images/ietf-dev-icon.bmp" />
|
||||
{% else %}
|
||||
|
@ -107,7 +103,6 @@ YAHOO.util.Event.onContentReady("wgs", function () {
|
|||
{% endblock %}
|
||||
//]]>
|
||||
</script>
|
||||
<script type="text/javascript" src="/js/base.js"></script>
|
||||
{% block js %}{% endblock %}
|
||||
|
||||
{% block content_end %}
|
||||
|
|
|
@ -38,17 +38,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<ul>
|
||||
<li class="sect first">Accounts</li>
|
||||
<li><a href="{% url account_index %}">{% if request.user.is_authenticated %}Manage Account{% else %}New Account{% endif %}</a></li>
|
||||
{% if user|in_group:"Area_Director" %}
|
||||
{% if user|has_role:"Area Director" %}
|
||||
<li class="sect first">AD Dashboard</li>
|
||||
<li><a href="{% url doc_search_by_ad name=user.get_profile.person.full_name_as_key %}">My Documents (old)</a></li>
|
||||
<li><a href="{% url doc_search_by_ad2 name=user.get_profile.person.full_name_as_key %}">My Documents (new)</a></li>
|
||||
<li><a href="{% url drafts_for_ad name=user.get_profile.full_name_as_key %}">My Documents</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.agenda_documents %}">Next Telechat</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.discusses %}">Discusses</a></li>
|
||||
<li><a href="{% url ietf.iesg.views.milestones_needing_review %}">Milestones</a></li>
|
||||
{# FIXME: this link should be removed when the old WG Actions are completely dead #}
|
||||
<li><a href="{% url ietf.iesg.views.working_group_actions %}">Working Groups</a></li>
|
||||
{% endif %}
|
||||
{% if user|in_group:"Secretariat" %}
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
<li class="sect first">Secretariat</li>
|
||||
<li><a href="/admin/iesg/telechatdate/">Telechat Dates</a></li>
|
||||
<li><a href="/admin/iesg/telechatagendaitem/">Management Items</a></li>
|
||||
|
@ -74,7 +73,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<li class="sect first">RFC Editor</li>
|
||||
<li><a href="{% url ietf.sync.views.discrepancies %}">Sync discrepancies</a></li>
|
||||
{% endif %}
|
||||
<li class="sect{% if not user|in_group:"Area_Director,Secretariat" %} first{% endif %}">Working Groups</li>
|
||||
<li class="sect{% if not user|has_role:"Area Director,Secretariat" %} first{% endif %}">Working Groups</li>
|
||||
|
||||
<li style="padding-bottom:0;"><div id="wgs" class="yuimenu"><div class="bd" style="border:0;">
|
||||
<ul class="first-of-type" style="padding:0;">
|
||||
|
@ -93,7 +92,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
<li class="sect">Drafts & RFCs</li>
|
||||
<li><a href="/doc/">Document search:</a></li>
|
||||
<li><form action="/doc/search/" method="get" style="padding-bottom:0;margin-bottom:0;"><input type="text" style="margin-left:10px; width:100px; border:1px solid #89d;" name="name" /><input type="hidden" name="activeDrafts" value="on"/><input type="hidden" name="rfcs" value="on"/></form></li>
|
||||
<li><form action="/doc/search/" method="get" style="padding-bottom:0;margin-bottom:0;"><input type="text" style="margin-left:10px; width:100px; border:1px solid #89d;" name="name" /><input type="hidden" name="activedrafts" value="on"/><input type="hidden" name="rfcs" value="on"/></form></li>
|
||||
<li><a href="{% url submit_index %}">Submit a draft</a></li>
|
||||
{% if user|in_group:"WG Chair" %}
|
||||
<li><a href="{% url submit_approvals %}">Approve a draft</a></li>
|
||||
|
|
14
ietf/templates/doc/ballot_popup.html
Normal file
14
ietf/templates/doc/ballot_popup.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
{% load ietf_filters %}
|
||||
<div class="ballot-popup">
|
||||
<div class="content">
|
||||
{{ ballot_content }}
|
||||
</div>
|
||||
<div class="actions">
|
||||
|
||||
{% if request.user|has_role:"Area Director" %}
|
||||
<a href="{% url ietf.idrfc.views_ballot.edit_position name=doc.name ballot_id=ballot_id %}" class="button" style="margin-right: 1em;">Edit Position</a>
|
||||
{% endif %}
|
||||
|
||||
<a href="" class="button close">Close</a>
|
||||
</div>
|
||||
</div>
|
|
@ -18,7 +18,7 @@ form.start-conflict-review .actions {
|
|||
{% block content %}
|
||||
<h1>Begin IETF conflict review for {{doc_to_review.canonical_name}}-{{doc_to_review.rev}}</h1>
|
||||
|
||||
<p class="helptext">For help on the initial state choice, see the <a href="{% url help_conflict_review_states %}">state table</a>.</p>
|
||||
<p class="helptext">For help on the initial state choice, see the <a href="{% url state_help type="conflict-review" %}">state table</a>.</p>
|
||||
|
||||
<form class="start-conflict-review" action="" method="post">
|
||||
<table>
|
||||
|
|
|
@ -226,10 +226,10 @@
|
|||
|
||||
<div class="links">
|
||||
<a href="mailto:{{ doc.name }}@tools.ietf.org?subject=Mail%20regarding%20{{ doc.name }}" rel="nofollow">Email Authors</a>
|
||||
| <a href="/ipr/search/?option=document_search&id={{ doc.name }}" rel="nofollow">IPR Disclosures</a>
|
||||
| <a href="{% url ipr_search %}?option=document_search&id={{ doc.name }}" rel="nofollow">IPR Disclosures</a>
|
||||
| <a href="http://www.fenron.net/~fenner/ietf/deps/index.cgi?dep={{ name }}" rel="nofollow">Dependencies to this document</a>
|
||||
| <a href="http://tools.ietf.org/idnits?url=http://tools.ietf.org/id/{{ doc.filename_with_rev }}" rel="nofollow" target="_blank">Check nits</a>
|
||||
| <a href="/feed/comments/{{ name }}/">History feed</a>
|
||||
| <a href="/feed/document-changes/{{ name }}/">History feed</a>
|
||||
| <a href="http://www.google.com/search?as_q={{ doc.name }}&as_sitesearch={{ search_archive }}" rel="nofollow" target="_blank">Search Mailing Lists</a>
|
||||
{% if user|has_role:"Area Director" %}
|
||||
| <a href="https://www.iesg.org/bin/c5i?mid=6&rid=77&target={{ doc.name }}" rel="nofollow" target="_blank">Search Mailing Lists (ARO)</a>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" type="text/css" href="/css/doc.css"></link>
|
||||
<link rel="alternate" type="application/atom+xml" href="/feed/comments/{{ doc.canonical_name }}/" />
|
||||
<link rel="alternate" type="application/atom+xml" href="/feed/document-changes/{{ doc.canonical_name }}/" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
15
ietf/templates/doc/drafts_for_ad.html
Normal file
15
ietf/templates/doc/drafts_for_ad.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Internet-Drafts and RFCs for {{ ad_name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Internet-Drafts and RFCs for {{ ad_name }}</h1>
|
||||
|
||||
{% include "idrfc/search_results.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
67
ietf/templates/doc/drafts_in_iesg_process.html
Normal file
67
ietf/templates/doc/drafts_in_iesg_process.html
Normal file
|
@ -0,0 +1,67 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block pagehead %}
|
||||
{% if last_call_only %}<link rel="alternate" type="application/atom+xml" href="/feed/last-call/">{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
th.area, td.area { text-align: left; padding-right: 0.5em; }
|
||||
th.date, td.date { text-align: left; padding-right: 0.5em; white-space: nowrap; }
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{% for state, docs in grouped_docs %}
|
||||
<h2 id="{{ state.slug }}">{{ state.name }}</h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th class="area">Area</th>
|
||||
<th class="date">{% if state.slug == "lc" %}Expires at{% else %}Date{% endif %}</th>
|
||||
</tr>
|
||||
|
||||
{% for doc in docs %}
|
||||
<tr class="doc">
|
||||
<td class="area">{% if doc.area_acronym %}{{ doc.area_acronym.upper }}{% endif %}</td>
|
||||
<td class="date">
|
||||
{% if state.slug == "lc" %}
|
||||
{% if doc.lc_expires %}{{ doc.lc_expires|date:"M j, Y" }}{% endif %}
|
||||
{% else %}
|
||||
{{ doc.time|date:"M j, Y" }}
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td>{{ doc.title }} ({{ doc.intended_std_level.name }})</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><a href="{% url doc_view doc.name %}">{{ doc.name }}</a></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>AD:</td>
|
||||
<td><a href="mailto:{{ doc.ad.email_address|urlencode }}">{{ doc.ad.plain_name }}</a></td>
|
||||
</tr>
|
||||
|
||||
{% if doc.note %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Note:</td>
|
||||
<td>{{ doc.note|linebreaksbr|urlize }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
15
ietf/templates/doc/drafts_in_last_call.html
Normal file
15
ietf/templates/doc/drafts_in_last_call.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Internet-Drafts in IETF Last Call{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Internet-Drafts in IETF Last Call</h1>
|
||||
|
||||
{% include "idrfc/search_results.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
36
ietf/templates/doc/index_active_drafts.html
Normal file
36
ietf/templates/doc/index_active_drafts.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block morecss %}
|
||||
.contents { max-width: 50em; }
|
||||
.contents a { float: left; width: 7em; margin-right: 2em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Active Internet-Drafts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Active Internet-Drafts</h1>
|
||||
|
||||
<p>This page lists all active Internet-Drafts, grouped by responsible
|
||||
group. For normal use, it is recommended to use the
|
||||
<a href="{% url doc_search %}">search page</a>.</p>
|
||||
|
||||
<p>There is also an <a href="{% url index_all_drafts %}">index of all
|
||||
Internet-Drafts</a> (that page also lists some machine-readable files
|
||||
for download).</p>
|
||||
|
||||
<p class="contents">
|
||||
{% for group in groups %}<a href="#{{ group.acronym }}">{{ group.acronym }}</a> {% endfor %}
|
||||
</p>
|
||||
|
||||
<div style="clear:left"></div>
|
||||
|
||||
{% for group in groups %}
|
||||
<h2 id="{{ group.acronym }}">{{ group.name }} ({{ group.acronym }})</h2>
|
||||
{% for d in group.active_drafts %}
|
||||
<p>{{ d.title }}<br>
|
||||
{% for a in d.authors %}{{ a }}{% if not forloop.last %}, {% endif %}{% endfor %}<br>
|
||||
<a href="/doc/{{ d.name }}/">{{ d.name }}-{{ d.rev }}</a> ({{ d.rev_time|date:"Y-m-d" }})</p>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
41
ietf/templates/doc/index_all_drafts.html
Normal file
41
ietf/templates/doc/index_all_drafts.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Index of all Internet-Drafts and RFCs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Index of all Internet-Drafts and RFCs</h1>
|
||||
|
||||
<p>This page lists all Internet-Drafts and RFCs. The main purpose of
|
||||
this page is to ensure all pages can be found by search engines. For
|
||||
normal use, it is recommended to use the <a href="{% url doc_search %}">search
|
||||
page</a>.</p>
|
||||
|
||||
<p>There's also an <a href="{% url index_active_drafts %}">index of
|
||||
active Internet-Drafts</a> with more information.</p>
|
||||
|
||||
<p>In addition, the following files are available for download:</p>
|
||||
<ul>
|
||||
<li><a href="http://www.ietf.org/id/1id-index.txt">Active Internet-Drafts (text)</a></li>
|
||||
<li><a href="http://www.ietf.org/id/1id-abstracts.txt">Active Internet-Drafts with abstracts (text)</a></li>
|
||||
<li><a href="http://www.ietf.org/id/all_id2.txt">All Internet-Drafts (tab-separated)</a>, <a href="http://www.ietf.org/id/all_id.txt">older version (with fewer fields)</a></li>
|
||||
<li><a href="http://www.rfc-editor.org/rfc/rfc-index.txt">All RFCs (text)</a></li>
|
||||
<li><a href="http://www.rfc-editor.org/rfc/rfc-index.xml">All RFCs (XML)</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Contents</h2>
|
||||
|
||||
<p>The documents are listed in the following categories:</p>
|
||||
|
||||
<ul>
|
||||
{% for state, heading, count, _ in categories %}
|
||||
<li><a href="#{{ state.slug }}">{{ heading }} ({{ count }})</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% for state, heading, count, links in categories %}
|
||||
<h3 id="{{ state.slug }}">{{ heading }} ({{ count }})</h3>
|
||||
|
||||
<p class="links">{{ links|safe }}</p>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
19
ietf/templates/doc/search.html
Normal file
19
ietf/templates/doc/search.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Search Internet-Drafts and RFCs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Search Internet-Drafts and RFCs</h1>
|
||||
|
||||
<div class="ietf-box search-form-box">
|
||||
{% include "idrfc/search_form.html" %}
|
||||
</div>
|
||||
|
||||
{% if meta.searching %}{% include "idrfc/search_results.html" %}{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
57
ietf/templates/doc/state_help.html
Normal file
57
ietf/templates/doc/state_help.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.ietf-table .name { white-space: nowrap; padding-right: 1em; }
|
||||
.ietf-table .desc { max-width: 35em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{% if state_type.slug == "draft-iesg" %}
|
||||
<p><a href="/images/iesg_draft_state_diagram.png">View Diagram</a></p>
|
||||
{% endif %}
|
||||
|
||||
<table class="ietf-table">
|
||||
<tr>
|
||||
<th>State</th>
|
||||
<th>Description</th>
|
||||
{% if has_next_states %}<th>Next State</th>{% endif %}
|
||||
</tr>
|
||||
|
||||
{% for state in states %}
|
||||
<tr id="{{ state.slug }}" class="{{ forloop.counter|divisibleby:2|yesno:"evenrow,oddrow" }}">
|
||||
<td class="name">{{ state.name }}</td>
|
||||
<td class="desc">{{ state.desc|linebreaksbr }}</td>
|
||||
{% if has_next_states %}
|
||||
<td class="name">
|
||||
{% for s in state.next_states.all %}
|
||||
{{ s.name }}<br/>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% if tags %}
|
||||
<h2>Tags</h2>
|
||||
|
||||
<table class="ietf-table">
|
||||
<tr>
|
||||
<th>Tag</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
{% for tag in tags %}
|
||||
<tr id="{{ tag.slug }}" class="{{ forloop.counter|divisibleby:2|yesno:"evenrow,oddrow" }}">
|
||||
<td class="name">{{ tag.name }}</td>
|
||||
<td class="desc">{{ tag.desc|linebreaksbr }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,31 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ title }} States{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.state_column {
|
||||
width: 13em;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>{{ title }} States</h1>
|
||||
|
||||
<table class="ietf-table">
|
||||
|
||||
<tr>
|
||||
<th class="state_column">State</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
||||
<tr class="{% cycle oddrow,evenrow as cycle1 %}"></tr>
|
||||
{% for state in states %}
|
||||
<tr class="{% cycle cycle1 %}">
|
||||
<td>{{ state.name|escape }}</td>
|
||||
<td>{{ state.desc|escape }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
|
@ -1,54 +1,46 @@
|
|||
{% comment %}
|
||||
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.
|
||||
{% endcomment %}
|
||||
{% load ietf_filters ietf_streams_redesign %}{% load ballot_icon_redesign %}{% load doc_states %}
|
||||
{% load ietf_filters %}{% load ballot_icon_redesign %}
|
||||
<td class="status">
|
||||
{{ doc.friendly_state|safe }} {% if not doc.rfc %}{{ doc|state_age_colored|safe }}{% endif %}
|
||||
{% if not hide_telechat_date %}{% if doc.telechat_date %}<br/>IESG Telechat: {{ doc.telechat_date }}{% endif %}{% endif %}
|
||||
{{ doc.friendly_state|safe }} {% if not doc.get_state_slug == "rfc" %}{{ doc|state_age_colored }}{% endif %}
|
||||
|
||||
{% block extra_status %}{% endblock %}
|
||||
{% if doc.rfc %}
|
||||
{%comment%}
|
||||
TODO: Port this block to Document when something that shows RFCs uses this template
|
||||
{% if doc.rfc.obsoleted_by %}<br />Obsoleted by {{ doc.rfc.obsoleted_by|urlize_ietf_docs }}{%endif %}
|
||||
{% if doc.rfc.updated_by %}<br />Updated by {{ doc.rfc.updated_by|urlize_ietf_docs }}{%endif %}
|
||||
{% if doc.rfc.has_errata %}<br /><a href="http://www.rfc-editor.org/errata_search.php?rfc={{doc.rfc.rfc_number}}" rel="nofollow">Errata</a>{% endif %}
|
||||
{%endcomment%}
|
||||
{% else %}{# not rfc #}
|
||||
{% if doc|rfc_editor_state %}<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{doc.name}}">{{ doc|rfc_editor_state|escape }}</a>{% endif %}
|
||||
{% stream_state doc %}
|
||||
{% endif %}
|
||||
{% if not hide_telechat_date and doc.telechat_date %}
|
||||
<br/>IESG Telechat: {{ doc.telechat_date }}
|
||||
{% endif %}
|
||||
|
||||
{% block extra_status %}{% endblock %}
|
||||
|
||||
|
||||
{% if doc.get_state_slug != "rfc" %}{# I-D #}
|
||||
|
||||
{% if doc|state:"draft-rfceditor" %}
|
||||
<br />RFC Editor State: <a href="http://www.rfc-editor.org/queue2.html#{{ doc.name }}">{{ doc|state:"draft-rfceditor" }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.stream %}
|
||||
<br />
|
||||
{% if doc|state:"stream" %}{{ doc|state:"stream" }}{% else %}{{ doc.stream }}{% endif %}
|
||||
|
||||
{% if doc.milestones %}
|
||||
{% for m in doc.milestones %}<span title="Part of {{ m.group.acronym }} milestone: {{ m.desc }}" class="milestone">{{ m.due|date:"M Y" }}</span>{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}{# RFC #}
|
||||
|
||||
{% if doc.obsoleted_by_list %}
|
||||
<div>Obsoleted by {{ doc.obsoleted_by_list|join:", "|urlize_ietf_docs }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.updated_by_list %}
|
||||
<div class="updated-by">Updated by {{ doc.updated_by_list|join:", "|urlize_ietf_docs }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.has_errata %}
|
||||
<div><a href="http://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" rel="nofollow">Errata</a></div>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="ballot">
|
||||
{% ballot_icon doc %}
|
||||
{% ballot_icon doc %}
|
||||
</td>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
{{ obj.comment_text|format_textarea|safe|truncatewords_html:"20" }}
|
|
@ -1,5 +0,0 @@
|
|||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
[{{ obj.get_username }}] {{ obj.comment_text|removetags:"b"|truncatewords:"15"|safe }}
|
||||
{% if obj.ballot %}[[ IESG {{ obj.get_ballot_display.upper }} ]]{% endif %}
|
||||
{% if not obj.document.rfc_flag %}[ version {{ obj.version }} ]{% endif %}
|
|
@ -1,3 +0,0 @@
|
|||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
{{ obj.ballot.last_call_text|escape|linebreaks }}
|
|
@ -1,2 +0,0 @@
|
|||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{{ obj }} ({{ obj.document.lc_sent_date|date:"F j" }}-{{ obj.document.lc_expiration_date|date:"F j, Y" }})
|
|
@ -4,8 +4,7 @@
|
|||
#
|
||||
# Description of fields:
|
||||
# 0 draft name and latest revision
|
||||
# 1 id_document_tag (internal database identifier; avoid using
|
||||
# unless you really need it)
|
||||
# 1 always -1 (was internal numeric database id in earlier schema)
|
||||
# 2 one of "Active", "Expired", "RFC", "Withdrawn by Submitter",
|
||||
# "Replaced", or "Withdrawn by IETF"
|
||||
# 3 if #2 is "Active", the IESG state for the document (such as
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
Internet-Drafts Status Summary
|
||||
|
||||
{% for item in in_track_ids %}{{ item.filename }}-{{ item.revision_display }} {{ item.revision_date|default_if_none:"" }} In IESG processing - ID Tracker state <{{ item.idstate }}> {# that last tab is on purpose #}
|
||||
{% endfor %}{%comment%}
|
||||
{%endcomment%}{% for item in active %}{{ item.filename }}-{{ item.revision_display }} {{ item.revision_date|default_if_none:"" }} {{ item.status.status }} {# keep that last tab #}
|
||||
{% endfor %}{%comment%}
|
||||
{%endcomment%}{% for item in published %}{{ item.filename }}-{{ item.revision_display }} {{ item.revision_date|default_if_none:"" }} {{ item.status.status }} {{ item.rfc_number }}
|
||||
{% endfor %}{%comment%}
|
||||
{%endcomment%}{% for item in expired %}{{ item.filename }}-{{ item.revision_display }} {{ item.revision_date|default_if_none:"" }} {{ item.status.status }} {# keep that last tab #}
|
||||
{% endfor %}{%comment%}
|
||||
{%endcomment%}{% for item in withdrawn_submitter %}{{ item.filename }}-{{ item.revision_display }} {{ item.revision_date|default_if_none:"" }} {{ item.status.status }} {# keep that last tab #}
|
||||
{% endfor %}{%comment%}
|
||||
{%endcomment%}{% for item in withdrawn_ietf %}{{ item.filename }}-{{ item.revision_display }} {{ item.revision_date|default_if_none:"" }} {{ item.status.status }} {# keep that last tab #}
|
||||
{% endfor %}{%comment%}
|
||||
{%endcomment%}{% for item in replaced %}{{ item.filename }}-{{ item.revision_display }} {{ item.revision_date|default_if_none:"" }} {{ item.status.status }} replaced by {% if item.replaced_by_id %}{{ item.replaced_by.filename }}{% else %}0{% endif %} {# and this one needs the trailing tab as well #}
|
||||
{% endfor %}
|
|
@ -1,9 +0,0 @@
|
|||
{% extends "idindex/id_index.txt" %}{% load ietf_filters %} {% block intro %} Current Internet-Drafts
|
||||
|
||||
This summary sheet provides a short synopsis of each Internet-Draft
|
||||
available within the "internet-drafts" directory at the shadow
|
||||
sites directory. These drafts are listed alphabetically by working
|
||||
group acronym and start date. Generated {{ time }}
|
||||
{% endblock %}{% block abstract %}
|
||||
|
||||
{{ draft.clean_abstract|indent|indent|safe }}{% endblock %}
|
|
@ -1,13 +1,12 @@
|
|||
{% autoescape off %}{% load ietf_filters %}{% block intro %} Current Internet-Drafts
|
||||
This summary sheet provides an index of each Internet-Draft
|
||||
These drafts are listed alphabetically by Working Group acronym and
|
||||
initial post date.
|
||||
{% endblock %}
|
||||
{% for group in groups|dictsort:"group_acronym.acronym" %}{% if group.active_drafts %}
|
||||
{{ group.group_acronym.name }} ({{ group.group_acronym.acronym}})
|
||||
{% filter dashify %}{{ group.group_acronym.name }} ({{ group.group_acronym.acronym}}){% endfilter %}
|
||||
{% for draft in group.active_drafts|stable_dictsort:"filename"|stable_dictsort:"start_date" %}
|
||||
{% filter id_index_wrap %}
|
||||
"{{draft.title.strip|clean_whitespace}}", {% for author in draft.authors.all|dictsort:"final_author_order" %}{{author.person}}, {% endfor %}{{draft.revision_date|date:"j-M-y"}}, <{{draft.filename}}-{{draft.revision}}{{draft.file_type|id_index_file_types}}>
|
||||
{% endfilter %}{% block abstract %}{% endblock %}
|
||||
{% endfor %}{%endif %}{% endfor %}{% endautoescape %}
|
||||
{% autoescape off %}{% load ietf_filters %} Current Internet-Drafts
|
||||
This summary sheet provides an index of each Internet-Draft. These
|
||||
drafts are listed alphabetically by Working Group acronym and initial
|
||||
post date. Generated {{ time }}.
|
||||
|
||||
{% for group in groups %}
|
||||
{% filter underline %}{{ group.name }} ({{ group.acronym }}){% endfilter %}
|
||||
{% for d in group.active_drafts %}
|
||||
{% filter wordwrap:72|indent:2 %}"{{ d.title|clean_whitespace }}", {% for a in d.authors %}{{ a }}, {% endfor %}{{ d.rev_time|date:"Y-m-d"}}, <{{ d.name }}-{{ d.rev }}{{ d.exts }}>
|
||||
{% endfilter %}{% if with_abstracts %}
|
||||
|
||||
{{ d.abstract.strip|unindent|fill:72|indent:6 }}{% endif %}{% endfor %}{% endfor %}{% endautoescape %}
|
||||
|
|
|
@ -58,7 +58,7 @@ the <a href="/doc/">search page</a> instead.</p>
|
|||
<p><a href="/doc/active/">More information about active Internet-Drafts</a></p>
|
||||
|
||||
<p>
|
||||
{% for doc in active %}<a href="/doc/{{ doc.filename }}/">{{ doc.filename }}</a><br/>
|
||||
{% for doc in active %}<a href="/doc/{{ doc.filename }}/">{{ doc.filename }}</a><br/>
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ form.change-state .actions {
|
|||
{% block content %}
|
||||
<h1>Change state of {{ doc }}</h1>
|
||||
|
||||
<p class="helptext">For help on the states, see the <a href="{% url help_states %}">state table</a>.</p>
|
||||
<p class="helptext">For help on the states, see the <a href="{% url state_help type="draft-iesg" %}">state table</a>.</p>
|
||||
|
||||
<form class="change-state" action="" method="post">
|
||||
<table>
|
||||
|
|
|
@ -61,7 +61,7 @@ td.ietf-main-intro { width:200px; background:#fff5df; padding:8px; border:1px so
|
|||
The IETF Datatracker is the IETF's web system for managing information
|
||||
about:
|
||||
<ul>
|
||||
<li><a href="/doc/">Internet-Drafts and RFCs</a></li>
|
||||
<li><a href="{% url doc_search %}">Internet-Drafts and RFCs</a></li>
|
||||
<li><a href="/ipr/">IPR disclosures</a></li>
|
||||
<li><a href="/liaison/">Liaison statements</a></li>
|
||||
<li><a href="/meeting/agenda/">Meeting agenda</a> and <a href="/meeting/">session agendas/slides/minutes</a></li>
|
||||
|
@ -70,14 +70,9 @@ about:
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="search_results" style="margin-top:8px;">
|
||||
{% if docs %}
|
||||
{% include "idrfc/search_results.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -32,7 +32,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
|
||||
<form id="search_form" class="search_form" action="/doc/search/" method="get">
|
||||
<form id="search_form" class="search_form" action="{% url doc_search %}" method="get">
|
||||
|
||||
<div class="search_field">
|
||||
<label>Name/number/title:</label> {{ form.name }}
|
||||
|
@ -42,18 +42,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<label>Types:</label>
|
||||
<table id="search_types">
|
||||
<tr><td><label>{{ form.rfcs }} RFCs</label></td></tr>
|
||||
<tr><td><label>{{ form.activeDrafts }} Internet-Drafts (active)</label></td></tr>
|
||||
<tr><td><label>{{ form.oldDrafts }} Internet-Drafts (expired/replaced/withdrawn)</label></td></tr>
|
||||
<tr><td><label>{{ form.activedrafts }} Internet-Drafts (active)</label></td></tr>
|
||||
<tr><td><label>{{ form.olddrafts }} Internet-Drafts (expired/replaced/withdrawn)</label></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{ form.sort }} {# hidden field #}
|
||||
|
||||
<b class="toggle_advanced"><img src="/images/{% if meta.advanced %}minus{% else %}plus{% endif %}.png" alt="" /> Advanced</b>
|
||||
|
||||
<div id="search_advanced" style="{% if not meta.advanced %}display:none;{%endif%}">
|
||||
Additional search criteria:
|
||||
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="author" {% if meta.by == "author" %}checked="checked"{% endif %}/> Author (last name):</label> {{ form.author }}
|
||||
<label><input type="radio" class="radio" name="by" value="author" {% if meta.by == "author" %}checked="checked"{% endif %}/> Author:</label> {{ form.author }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="group" {% if meta.by == "group" %}checked="checked"{% endif %}/> WG:</label> {{ form.group }}
|
||||
|
@ -65,7 +67,7 @@ Additional search criteria:
|
|||
<label><input type="radio" class="radio" name="by" value="ad" {% if meta.by == "ad" %}checked="checked"{% endif %}/> Responsible AD:</label> {{ form.ad }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="state" {% if meta.by == "state" %}checked="checked"{% endif %}/> IESG State:</label> {{ form.state }} :: {{ form.subState }}
|
||||
<label><input type="radio" class="radio" name="by" value="state" {% if meta.by == "state" %}checked="checked"{% endif %}/> IESG State:</label> {{ form.state }} :: {{ form.substate }}
|
||||
</div>
|
||||
|
||||
</div><!-- end of advanced -->
|
||||
|
|
|
@ -42,13 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% include "idrfc/search_form.html" %}
|
||||
</div>
|
||||
|
||||
<div id="search_results">
|
||||
<div id="search-results">
|
||||
{% if meta.searching %}
|
||||
{% include "idrfc/search_results.html" %}
|
||||
{% include "idrfc/search-results.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -37,30 +37,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
|
||||
{% if show_add_to_list and user.is_authenticated %}
|
||||
<td class="addtolist">
|
||||
{% if doc.id %}
|
||||
<a href="{% url community_add_document doc.id.draft_name %}" title="Add to your personal ID list"><img src="/images/add_to_list.png" alt="Add to your personal ID list" /></a>
|
||||
{% else %}
|
||||
<a href="{% url community_add_document doc.rfc.filename %}" title="Add to your personal ID list"><img src="/images/add_to_list.png" alt="Add to your personal ID list" /></a>
|
||||
{% endif %}
|
||||
<a href="{% url community_add_document doc.name %}" title="Add to your personal ID list"><img src="/images/add_to_list.png" alt="Add to your personal ID list" /></a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="doc">
|
||||
{% if doc.rfc %}{{ doc.rfc.displayname_with_link|safe }}
|
||||
{% if doc.id %}<br />(<a href="{{ doc.id.get_absolute_url }}">{{doc.id.draft_name}}</a>){%endif%}
|
||||
{% else %}{{ doc.id.displayname_with_link|safe }}
|
||||
{% endif %}
|
||||
<a href="{{ doc.get_absolute_url }}">{% if doc.get_state_slug == "rfc" %}RFC {{ doc.rfc_number }}{% else %}{{ doc.name }}-{{ doc.rev }}{% endif %}</a>
|
||||
|
||||
{% if doc.get_state_slug == "rfc" and "draft" in doc.name %}
|
||||
<br/><i>(was {{ doc.name }})</i>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="title">{{ doc.title }}</td>
|
||||
|
||||
<td class="date">{% if not doc.rfc %}{{ doc.publication_date }}{% else %}{{ doc.publication_date|date:"Y-m" }}{% endif %}
|
||||
{% if doc.publication_date|timesince_days|new_enough:request %}<br/><span class="ietf-small ietf-highlight-y">{% if not doc.rfc%}<a href="http:{{rfcdiff_prefix}}?url2={{doc.id.draft_name_and_revision}}">new</a>{%else%}new{%endif%}</span>{%endif%}
|
||||
{% if doc.id and doc.id.expected_expiration_date and doc.id.expected_expiration_date|timesince_days|expires_soon:request %}<br/><span class="ietf-small ietf-highlight-y">expires soon</span>{%endif%}
|
||||
<td class="date">
|
||||
{% if doc.get_state_slug == "rfc" %}{{ doc.latest_revision_date|date:"Y-m" }}{% else %}{{ doc.latest_revision_date|date:"Y-m-d" }}{% endif %}
|
||||
|
||||
{% if doc.latest_revision_date|timesince_days|new_enough:request %}
|
||||
<div class="ietf-small ietf-highlight-y"><a{% if doc.get_state_slug != "rfc" %} href="http:{{ rfcdiff_prefix }}?url2={{ doc.name }}-{{ doc.rev }}"{% endif %}>new</a></div>
|
||||
{% endif %}
|
||||
|
||||
{% if doc.get_state_slug == "active" and doc.expirable and doc.expires|timesince_days|expires_soon:request %}
|
||||
<div class="ietf-small ietf-highlight-y">expires soon</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
{% include "idrfc/status_columns.html" %}
|
||||
{% include "idrfc/ipr_column.html" %}
|
||||
{# <td class="ad">{% if doc.ad_name %}{{ doc.ad_name }}{% else %} {% endif %}</td> #}
|
||||
<td class="ad">{{ doc.ad_name|default:"" }}
|
||||
{% if doc.id.underlying_document.shepherd %}<br/>{{ doc.id.underlying_document.shepherd.plain_name|default:""}}{% endif %}
|
||||
{% include "doc/status_columns.html" %}
|
||||
|
||||
<td class="ipr">
|
||||
{% if doc.iprs %}
|
||||
<a href="{% url ipr_search %}?option=document_search&id={{ doc.name }}">{{ doc.iprs|length }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td class="ad">{{ doc.ad|default:"" }}</td>
|
||||
|
||||
</tr>
|
||||
|
|
|
@ -32,36 +32,42 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
|
||||
{% if meta.max %}
|
||||
<p><b>Too many documents match the query! Returning partial result only.</b></p>
|
||||
{% endif %}
|
||||
<div class="search-results">
|
||||
|
||||
{% if not docs %}
|
||||
<p><b>No documents match your query.</b></p>
|
||||
<h2>No documents match your query.</h2>
|
||||
{% else %}
|
||||
|
||||
{% if meta.max %}
|
||||
<h2>Too many documents match the query! Returning partial result only.</h2>
|
||||
{% endif %}
|
||||
|
||||
<table class="ietf-table ietf-doctable">
|
||||
<tr>
|
||||
{% if user.is_authenticated %}<th></th>{% endif %}
|
||||
{% if show_add_to_list and user.is_authenticated %}<th></th>{% endif %}
|
||||
|
||||
{% for hdr in meta.hdrs %}
|
||||
<th class="{{ hdr.htype }}" {% if hdr.colspan %}colspan="{{ hdr.colspan }}"{% endif %}>
|
||||
{{ hdr.htitle }}
|
||||
|
||||
<a href="{{ meta.rqps }}&sortBy={{hdr.htype}}"><img src="/images/sort-header-{% if hdr.selected %}filled{% else %}clear{% endif %}.png"/></a>
|
||||
{% for h in meta.headers %}
|
||||
<th class="{{ h.key }}" {% if h.colspan %}colspan="{{ h.colspan }}"{% endif %}>
|
||||
{% if "sort_url" in h %}
|
||||
<a href="{{ h.sort_url }}">{{ h.title }}
|
||||
<img src="/images/sort-header-{% if h.sorted %}filled{% else %}clear{% endif %}.png"/></a>
|
||||
{% else %}
|
||||
{{ h.title }}
|
||||
{% endif %}
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
<!-- <tr><th></th><th class="doc">Document</th><th class="title">Title</th><th class="date">Date</th><th class="status" colspan="2">Status</th><th class="ad">Area Director</th></tr> -->
|
||||
{% regroup docs by view_sort_group as grouped_docs %}
|
||||
|
||||
{% regroup docs by search_heading as grouped_docs %}
|
||||
|
||||
{% for doc_group in grouped_docs %}
|
||||
<tr class="header"><td colspan="7">{{ doc_group.grouper }}s</td></tr>
|
||||
|
||||
{% with 1 as show_add_to_list %}
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
<tr class="header"><td colspan="10">{{ doc_group.grouper }}</td></tr>
|
||||
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -31,7 +31,7 @@ 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.
|
||||
{% endcomment %}
|
||||
{% load ietf_filters ietf_streams %}{% load ballot_icon %}
|
||||
{% load ietf_filters ietf_streams %}{% load ballot_icon_redesign %}
|
||||
<td class="status">
|
||||
{{ doc.friendly_state|safe }} {% if not doc.rfc %}{{ doc.id|state_age_colored|safe }}{% endif %}
|
||||
{% if not hide_telechat_date %}{% if doc.telechat_date %}<br/>IESG Telechat: {{ doc.telechat_date }}{% endif %}{% endif %}
|
||||
|
|
1
ietf/templates/idtracker/.gitignore
vendored
1
ietf/templates/idtracker/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/*.pyc
|
|
@ -1,25 +0,0 @@
|
|||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
<tr>{% if doc.primary_flag %}
|
||||
<td>{{ doc.area_acronym.area_acronym.acronym.upper }}</td>
|
||||
<td nowrap>
|
||||
{% ifequal doc.cur_state.state "In Last Call" %}
|
||||
{% if doc.document.lc_expiration_date %}
|
||||
{{ doc.document.lc_expiration_date|date:"M j" }}, {{ doc.document.lc_expiration_date|date:"Y" }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if doc.status_date %}
|
||||
{{ doc.status_date|date:"M j" }}, {{ doc.status_date|date:"Y" }}
|
||||
{% endif %}
|
||||
{% endifequal %}</td>
|
||||
{% else %}
|
||||
<td></td><td></td>
|
||||
{% endif %}
|
||||
<td>{{ doc.document.title|escape }} ({{ doc.document.intended_status|escape }})</td></tr>
|
||||
<tr><td></td><td></td><td><a href="/doc/{{ doc.document.filename }}/">{{ doc.document.displayname|safe }}</a></td></tr>
|
||||
{% if doc.primary_flag %}
|
||||
<tr><td></td><td>Token:</td><td><a href="mailto:{{ doc.token_email|urlencode }}">{{ doc.token_name }}</a></td></tr>
|
||||
{% if doc.note %}
|
||||
<tr><td></td><td>Note:</td><td>{{ doc.note|linebreaksbr|urlize }}</td></tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
|
@ -1,10 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ state.state }}</h1>
|
||||
{{ state.description|escape }}
|
||||
<form action=".">
|
||||
<input type="button" value="Back" onClick="history.go(-1);"/>
|
||||
</form>
|
||||
{% endblock%}
|
|
@ -1,61 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
|
||||
{% block title %}Internet Draft States{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>Main I-D States</h1>
|
||||
|
||||
<p><a href="/images/state_diagram.png">View Diagram</a></p>
|
||||
|
||||
<table class="ietf-table">
|
||||
|
||||
<tr>
|
||||
<th>State</th>
|
||||
<th>Description</th>
|
||||
<th>Next State(s)</th>
|
||||
</tr>
|
||||
|
||||
{# XXX I-D Exists should be added to the database #}
|
||||
<tr class="{% cycle oddrow,evenrow as cycle1 %}">
|
||||
<tr>
|
||||
<td>I-D Exists</td>
|
||||
<td >Initial (default) state for all internet drafts. Such documents are
|
||||
not being tracked by the IESG as no request has been made of the
|
||||
IESG to do anything with the document.</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li> AD is watching
|
||||
<li> Publication Requested</ul>
|
||||
</td></tr>
|
||||
|
||||
{% for state in states %}
|
||||
<tr class="{% cycle cycle1 %}">
|
||||
<td>{{ state.state|escape }}</td>
|
||||
<td>{{ state.description|escape }}</td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for next in state.nextstate.all %}
|
||||
<li>{{ next.next_state.state }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<h2>Sub States</h2>
|
||||
<table class="ietf-table">
|
||||
|
||||
<tr><th>Sub State Name</th><th>Description</th></tr>
|
||||
|
||||
{% for substate in substates %}
|
||||
<tr class="{% cycle oddrow,evenrow %}">
|
||||
<td>{{ substate.sub_state|escape }}</td>
|
||||
<td>{{ substate.description|escape }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
|
@ -1,28 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
|
||||
{% block pagehead %}{% if lastcall %}
|
||||
<link rel="alternate" type="application/atom+xml" href="/feed/last-call/">
|
||||
{% endif %}{% endblock %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
{% regroup object_list by cur_state_id as grouped %}
|
||||
{% for state in grouped %}
|
||||
<a name="grp{{ state.list.0.cur_state }}"><h2>{{ state.list.0.cur_state }}</h2></a>
|
||||
<table>
|
||||
<tr><th>Area</th><th>{% ifequal state.list.0.cur_state.state "In Last Call" %}Expires at{% else %}Date{% endifequal %}</th></tr>
|
||||
{% for doc in state.list %}
|
||||
{% include "idtracker/document_entry.html" %}
|
||||
{% if doc.ballot_others %}
|
||||
{% for doc in doc.ballot_others %}
|
||||
{% include "idtracker/document_entry.html" %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
|
@ -110,3 +110,8 @@ div.agenda-wg { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width
|
|||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -170,5 +170,7 @@ font-size:80%; font-style:italic;
|
|||
{% endblock content %}
|
||||
|
||||
{% block content_end %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
<script type="text/javascript" src="/js/agenda-documents.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -112,3 +112,8 @@ if (url[1] == 'byme') {
|
|||
}
|
||||
{% endif %}{# user in_group #}
|
||||
{% endblock scripts %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -21,7 +21,7 @@ form.change-state .actions {
|
|||
<h1>{{ title }}</h1>
|
||||
|
||||
{% if not option %}
|
||||
<p class="helptext">For help on the states, see the <a href="{% url help_charter_states %}">state table</a>.</p>
|
||||
<p class="helptext">For help on the states, see the <a href="{% url state_help type="charter" %}">state table</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
<form class="change-state" action="" method="post">
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
{% block content %}
|
||||
{% load ietf_filters %}
|
||||
{% load ballot_icon %}
|
||||
|
||||
<h1>Bofs</h1>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
{% block content %}
|
||||
{% load ietf_filters %}
|
||||
{% load ballot_icon %}
|
||||
{% load ballot_icon_redesign %}
|
||||
|
||||
<h1>Chartering or Re-Chartering Working Groups</h1>
|
||||
|
||||
|
@ -51,3 +51,8 @@
|
|||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -35,72 +35,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
{% block wg_titledetail %}Documents{% endblock %}
|
||||
|
||||
{% block wg_content %}
|
||||
<div class="group-documents">
|
||||
|
||||
{% regroup docs by view_sort_group as grouped_docs %}
|
||||
{% include "idrfc/search_results.html" %}
|
||||
|
||||
<table class="ietf-table ietf-doctable" style="margin-top:16px;">
|
||||
<tr>
|
||||
{% if user.is_authenticated %}<th></th>{% endif %}
|
||||
<th class="doc">Document</th><th class="title">Title</th><th class="date">Date</th><th class="status" colspan="2">Status</th><th class="ipr">ipr</th><th class="ad">AD / Shepherd</th>
|
||||
</tr>
|
||||
{% for doc_group in grouped_docs %}
|
||||
<tr class="header"><td colspan="7">{{doc_group.grouper}}s</td></tr>
|
||||
|
||||
{% with 1 as show_add_to_list %}
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% regroup docs_related by view_sort_group as grouped_docs_related %}
|
||||
|
||||
<table class="ietf-table ietf-doctable" style="margin-top:16px;">
|
||||
<tr>
|
||||
{% if user.is_authenticated %}<th></th>{% endif %}
|
||||
<th class="doc">Related Documents</th><th class="title">Title</th><th class="date">Date</th><th class="status" colspan="2">Status</th><th class="ipr">ipr</th><th class="ad">AD / Shepherd</th>
|
||||
</tr>
|
||||
{% for doc_group in grouped_docs_related %}
|
||||
<tr class="header"><td colspan="7">{{doc_group.grouper}}s</td></tr>
|
||||
|
||||
{% with 1 as show_add_to_list %}
|
||||
{% for doc in doc_group.list %}
|
||||
{% include "idrfc/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% with docs_related as docs %}{% include "idrfc/search_results.html" %}{% endwith %}
|
||||
|
||||
</div>
|
||||
{% endblock wg_content %}
|
||||
|
||||
{% block scripts %}
|
||||
YAHOO.util.Event.onContentReady("search_submit_button", function () {
|
||||
var oButton = new YAHOO.widget.Button("search_submit_button", {});
|
||||
});
|
||||
(function ($) {
|
||||
$(document).ready(function () {
|
||||
$('.addtolist a').click(function() {
|
||||
var trigger = $(this);
|
||||
$.ajax({
|
||||
url: trigger.attr('href'),
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
success: function(response){
|
||||
if (response.success) {
|
||||
trigger.replaceWith('added');
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
{% endblock scripts %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/doc-search.js"></script>
|
||||
{% endblock %}
|
||||
|
|
15
ietf/urls.py
15
ietf/urls.py
|
@ -5,13 +5,12 @@ from django.conf.urls.defaults import patterns, include, handler404, handler500
|
|||
from django.contrib import admin
|
||||
|
||||
from ietf.iesg.feeds import IESGAgenda
|
||||
from ietf.idtracker.feeds import DocumentComments, InLastCall
|
||||
from ietf.doc.feeds import DocumentChanges, InLastCall
|
||||
from ietf.ipr.feeds import LatestIprDisclosures
|
||||
from ietf.proceedings.feeds import LatestWgProceedingsActivity
|
||||
from ietf.liaisons.feeds import Liaisons
|
||||
from ietf.wgcharter.feeds import GroupChanges
|
||||
|
||||
from ietf.idtracker.sitemaps import IDTrackerMap, DraftMap
|
||||
from ietf.liaisons.sitemaps import LiaisonMap
|
||||
from ietf.ipr.sitemaps import IPRMap
|
||||
from ietf.announcements.sitemaps import NOMCOMAnnouncementsMap
|
||||
|
@ -25,7 +24,7 @@ admin.site.disable_action('delete_selected')
|
|||
feeds = {
|
||||
'iesg-agenda': IESGAgenda,
|
||||
'last-call': InLastCall,
|
||||
'comments': DocumentComments,
|
||||
'document-changes': DocumentChanges,
|
||||
'group-changes': GroupChanges,
|
||||
'ipr': LatestIprDisclosures,
|
||||
'liaison': Liaisons,
|
||||
|
@ -33,16 +32,11 @@ feeds = {
|
|||
}
|
||||
|
||||
sitemaps = {
|
||||
'idtracker': IDTrackerMap,
|
||||
'drafts': DraftMap,
|
||||
'liaison': LiaisonMap,
|
||||
'ipr': IPRMap,
|
||||
'nomcom-announcements': NOMCOMAnnouncementsMap,
|
||||
}
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
del sitemaps['drafts'] # not needed, overlaps sitemaps['idtracker']
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', 'ietf.idrfc.views.main'),
|
||||
(r'^accounts/', include('ietf.ietfauth.urls')),
|
||||
|
@ -52,10 +46,11 @@ urlpatterns = patterns('',
|
|||
(r'^community/', include('ietf.community.urls')),
|
||||
(r'^cookies/', include('ietf.cookies.urls')),
|
||||
(r'^doc/', include('ietf.idrfc.urls')),
|
||||
(r'^drafts/', include('ietf.idindex.urls')),
|
||||
(r'^drafts/', include('ietf.doc.redirect_drafts_urls')),
|
||||
(r'^feed/comments/(?P<remainder>.*)/$', 'django.views.generic.simple.redirect_to', { 'url': '/feed/document-changes/%(remainder)s/'}),
|
||||
(r'^feed/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', { 'feed_dict': feeds}),
|
||||
(r'^help/', include('ietf.help.urls')),
|
||||
(r'^idtracker/', include('ietf.idtracker.urls')),
|
||||
(r'^idtracker/', include('ietf.doc.redirect_idtracker_urls')),
|
||||
(r'^iesg/', include('ietf.iesg.urls')),
|
||||
(r'^ipr/', include('ietf.ipr.urls')),
|
||||
(r'^liaison/', include('ietf.liaisons.urls')),
|
||||
|
|
|
@ -418,6 +418,7 @@ def make_test_data():
|
|||
docalias = DocAlias.objects.create(name=doc.name, document=doc)
|
||||
doc.stream = StreamName.objects.get(slug='irtf')
|
||||
doc.save()
|
||||
doc.set_state(State.objects.get(type="draft", slug="active"))
|
||||
crdoc = Document.objects.create(name='conflict-review-imaginary-irtf-submission', type_id='conflrev', rev='00', notify="fsm@ietf.org")
|
||||
DocAlias.objects.create(name=crdoc.name, document=crdoc)
|
||||
crdoc.set_state(State.objects.get(name='Needs Shepherd', type__slug='conflrev'))
|
||||
|
|
|
@ -38,7 +38,7 @@ from django.http import HttpResponse
|
|||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from ietf.idtracker.models import Area, IETFWG
|
||||
from ietf.idrfc.views_search import SearchForm, search_query
|
||||
from ietf.idrfc.views_search import SearchForm, retrieve_search_results
|
||||
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper
|
||||
from ietf.ipr.models import IprDetail
|
||||
from ietf.group.models import Group
|
||||
|
@ -146,39 +146,34 @@ def wg_documents(request, acronym):
|
|||
concluded = wg.status_id in [ 2, 3, ]
|
||||
proposed = (wg.status_id == 4)
|
||||
form = SearchForm({'by':'group', 'group':str(wg.group_acronym.acronym),
|
||||
'rfcs':'on', 'activeDrafts':'on'})
|
||||
if not form.is_valid():
|
||||
raise ValueError("form did not validate")
|
||||
(docs,meta) = search_query(form.cleaned_data)
|
||||
'rfcs':'on', 'activedrafts':'on'})
|
||||
docs, meta = retrieve_search_results(form)
|
||||
|
||||
# get the related docs
|
||||
form_related = SearchForm({'by':'group', 'name':'-'+str(wg.group_acronym.acronym)+'-', 'activeDrafts':'on'})
|
||||
if not form_related.is_valid():
|
||||
raise ValueError("form_related did not validate")
|
||||
(docs_related,meta_related) = search_query(form_related.cleaned_data)
|
||||
form_related = SearchForm({'by':'group', 'name':'-'+str(wg.group_acronym.acronym)+'-', 'activedrafts':'on'})
|
||||
docs_related, meta_related = retrieve_search_results(form_related)
|
||||
docs_related_pruned = []
|
||||
for d in docs_related:
|
||||
parts = d.id.draft_name.split("-", 2);
|
||||
parts = d.name.split("-", 2);
|
||||
# canonical form draft-<name|ietf>-wg-etc
|
||||
if ( len(parts) >= 3):
|
||||
if parts[1] != "ietf" and parts[2].startswith(wg.group_acronym.acronym+"-"):
|
||||
if len(parts) >= 3 and parts[1] != "ietf" and parts[2].startswith(wg.group_acronym.acronym + "-"):
|
||||
docs_related_pruned.append(d)
|
||||
|
||||
docs_related = docs_related_pruned
|
||||
|
||||
# move call for WG adoption to related
|
||||
cleaned_docs = []
|
||||
related_doc_names = set(d.id.draft_name for d in docs_related)
|
||||
docs_related_names = set(d.name for d in docs_related)
|
||||
for d in docs:
|
||||
if d.id and d.id._draft and d.id._draft.stream_id == "ietf" and d.id._draft.get_state_slug("draft-stream-ietf") == "c-adopt":
|
||||
if d.id.draft_name not in related_doc_names:
|
||||
if d.stream_id == "ietf" and d.get_state_slug("draft-stream-ietf") == "c-adopt":
|
||||
if d.name not in docs_related_names:
|
||||
docs_related.append(d)
|
||||
else:
|
||||
cleaned_docs.append(d)
|
||||
|
||||
docs = cleaned_docs
|
||||
|
||||
docs_related.sort(key=lambda d: d.id.draft_name)
|
||||
docs_related.sort(key=lambda d: d.name)
|
||||
|
||||
return wg, concluded, proposed, docs, meta, docs_related, meta_related
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
*/
|
||||
|
||||
body { margin: 0; }
|
||||
|
||||
a img { border: 0; }
|
||||
|
||||
.yui-skin-sam h1 {margin: 0.5em 0; font-size: 167%;}
|
||||
.yui-skin-sam .yui-navset .yui-content {
|
||||
background: white;
|
||||
|
@ -114,7 +117,8 @@ table.ietf-table { border-collapse:collapse; border:1px solid #7f7f7f; }
|
|||
.ietf-doctable tr.header { border-top: 1px solid #7f7f7f; border-bottom: 1px solid #7f7f7f; border-left: 1px solid white; border-right:2px solid white;}
|
||||
.ietf-doctable tr.header td {padding: 6px 6px; font-weight: bold; }
|
||||
.ietf-doctable table { max-width: 1200px; }
|
||||
.ietf-doctable th { cursor: pointer; white-space: nowrap; }
|
||||
.ietf-doctable th { white-space: nowrap; }
|
||||
.ietf-doctable th a { text-decoration: none; color: #fff; }
|
||||
.ietf-doctable th img { border-style: none; vertical-align: top; }
|
||||
.ietf-doctable th.doc, .ietf-doctable td.doc { min-width:20em; max-width: 35em; }
|
||||
.ietf-doctable th.title, .ietf-doctable td.title { min-width: 20em; max-width: 35em; }
|
||||
|
@ -123,10 +127,11 @@ table.ietf-table { border-collapse:collapse; border:1px solid #7f7f7f; }
|
|||
.ietf-doctable th.ipr { font-variant: small-caps; }
|
||||
.ietf-doctable th.ad, .ietf-doctable td.ad { white-space:nowrap; min-width: 6em; }
|
||||
.ietf-doctable td.ballot { border-left: hidden; min-width: 37px; }
|
||||
.ietf-doctable td .updated-by { max-width: 20em; } /* some RFCs have really long lists */
|
||||
|
||||
table.ballot_icon { empty-cells: show; padding: 0; border-spacing: 0; border: 1px solid black; border-collapse: collapse; table-layout:fixed; min-width:35px; background:white; }
|
||||
table.ballot_icon td { border: 1px solid black; height: 7px; width: 6px; padding: 0;}
|
||||
table.ballot_icon td.my { border: 3px outset black;}
|
||||
.ietf-doctable .status .milestone,
|
||||
.ietf-box .stream-state .milestone
|
||||
{ display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; }
|
||||
|
||||
.ietf-small { font-size:85%; }
|
||||
.ietf-tiny { font-size:70%; }
|
||||
|
@ -134,7 +139,8 @@ table.ballot_icon td.my { border: 3px outset black;}
|
|||
.ietf-highlight-r { padding:0 2px;background:#ffa0a0;}
|
||||
.ietf-divider { background: #2647a0; color: white; font-size:116%; padding:0.5em 1em; }
|
||||
|
||||
table.history .snippet .showAll { color: blue; cursor: pointer; }
|
||||
|
||||
table.history .snippet .show-all { color: blue; cursor: pointer; }
|
||||
|
||||
.error-text {
|
||||
font-size: 1.095em;
|
||||
|
@ -175,14 +181,18 @@ form table .help {
|
|||
.warning { color: #a00; }
|
||||
|
||||
.position-discuss,
|
||||
.position-block { background-color: #c00000;}
|
||||
.position-yes { background-color: #80ff80;}
|
||||
.position-noobj { background-color: #80ff80;}
|
||||
.position-abstain { background-color: #ffff00;}
|
||||
.position-recuse { background-color: #c0c0c0;}
|
||||
.position-norecord { background-color: #ffffff;}
|
||||
.position-block { background-color: #c00;}
|
||||
.position-yes { background-color: #0d0;}
|
||||
.position-noobj { background-color: #0d0;}
|
||||
.position-abstain { background-color: #ff0;}
|
||||
.position-recuse { background-color: #bbb;}
|
||||
.position-norecord { background-color: #fff;}
|
||||
|
||||
.ballot-sidebar { width: 160px; float: left; margin-top: 0.4em; margin-right: 1em; padding: 0.5em; background: #edf5ff; }
|
||||
.ballot-icon table { empty-cells: show; padding: 0; border-spacing: 0; border: 1px solid #666; border-collapse: collapse; table-layout: fixed; min-width: 35px; background: #fff; }
|
||||
.ballot-icon table td { border: 1px solid #666; height: 7px; width: 6px; padding: 0;}
|
||||
.ballot-icon table td.my { border: 3px solid #000;}
|
||||
|
||||
.ballot-sidebar { width: 160px; float: left; margin-top: 0.4em; padding: 5px; background: #edf5ff; }
|
||||
.ballot-sidebar .action { margin-bottom: 1em; }
|
||||
.ballot-sidebar .position-group { margin-bottom: 1em; }
|
||||
.ballot-sidebar .position-group .heading { font-weight: bold; }
|
||||
|
@ -190,15 +200,14 @@ form table .help {
|
|||
.ballot-sidebar .position-group .was { padding-left: 10px; font-size:85%; }
|
||||
.ballot-sidebar .position-group:last-child { margin-bottom: 0; }
|
||||
|
||||
.ballot-content { margin-left: 180px; }
|
||||
.ballot-content { margin-left: 180px; } /* this positions the content to the right of the sidebar */
|
||||
.ballot-content .other-ballots { margin: 1em 0 2em 0; }
|
||||
.ballot-content .other-ballots a { display: inline-block; margin-right: 0.5em; }
|
||||
|
||||
#ballot_dialog_body { background-color: #fff; }
|
||||
#ballot_dialog_body .ballot-sidebar { margin-top: 0; }
|
||||
|
||||
.ballot-content h2.ad-ballot-comment { background: #2647A0; color: #fff; padding: 2px 4px; font-size: 108%; margin-top: 0;}
|
||||
|
||||
.ballot-popup > .content { width: 860px; height: 500px; overflow: auto; background: #fff; border: 1px solid #ccc; }
|
||||
.ballot-popup .ballot-sidebar { margin-top: 0; }
|
||||
|
||||
ul.messages { border: solid black 1px; margin: 0.4em 0; padding: 1em; }
|
||||
li.debug { margin: 0.5em; background-color: #ccf; }
|
||||
li.info { margin: 0.5em; background-color: #ff8; }
|
||||
|
@ -208,12 +217,17 @@ li.error { margin: 0.5em; background-color: #f44; }
|
|||
|
||||
.errorlist { background: red; color: white; padding: 0.2ex 0.2ex 0.2ex 0.5ex; border: 0px; margin: 0px; font-family: Arial, sans-serif; }
|
||||
|
||||
.group-documents .search-results { margin-top: 1.5em; }
|
||||
|
||||
table.milestones td.due { vertical-align: top; width: 80px; }
|
||||
table.milestones .doc { display: block; padding-left: 1em; }
|
||||
|
||||
.stream-state .milestone { display: inline-block; font-size: smaller; background-color: #d5dde6; padding: 0 0.2em; margin-left: 0.3em; }
|
||||
|
||||
.button, .button:hover:disabled {
|
||||
#modal-box { background: #f0f0f0; border-radius: 2px; padding: 10px; box-shadow: 0 0 4px rgba(0, 0, 0, 0.8); }
|
||||
|
||||
#modal-box .actions { padding-top: 1em; text-align: right; }
|
||||
|
||||
.button {
|
||||
display: inline-block; padding: 4px 12px; margin-right: 0.3em;
|
||||
color: #222; font-weight: normal; text-align: center; text-decoration: none; outline: none; cursor: pointer;
|
||||
background: #eee; background: linear-gradient(#fff, #e0e0e0); background: -webkit-linear-gradient(#fff, #e0e0e0); background: -moz-linear-gradient(#fff, #e0e0e0);
|
||||
|
@ -222,4 +236,4 @@ table.milestones .doc { display: block; padding-left: 1em; }
|
|||
}
|
||||
.button:hover { color: #111; background: #ddd; background: linear-gradient(#eee, #ccc); background: -webkit-linear-gradient(#eee, #ccc); background: -moz-linear-gradient(#eee, #ccc); }
|
||||
.button:active { color: #000; background: #ccc; }
|
||||
.button:disabled, .button:hover:disabled { color: #999; cursor: default; }
|
||||
.button:disabled, .button:hover:disabled { color: #999; cursor: default; background: #eee; background: linear-gradient(#fff, #e0e0e0); background: -webkit-linear-gradient(#fff, #e0e0e0); background: -moz-linear-gradient(#fff, #e0e0e0); }
|
||||
|
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
@ -4,7 +4,7 @@
|
|||
<Description>Use datatracker.ietf.org to search for Internet-Drafts and RFCs</Description>
|
||||
<Tags>Requests For Comments</Tags>
|
||||
<Url type="text/html"
|
||||
template="http://datatracker.ietf.org/doc/search/?name={searchTerms}&activeDrafts=on&rfcs=on&lucky=on"/>
|
||||
template="http://datatracker.ietf.org/doc/search/?name={searchTerms}&activedrafts=on&rfcs=on"/>
|
||||
<LongName>datatracker.ietf.org RFC and Internet-Draft Search</LongName>
|
||||
<Image height="16" width="16" type="image/vnd.microsoft.icon">http://datatracker.ietf.org/images/ietf-icon-blue.bmp</Image>
|
||||
<Developer>Tony Hansen</Developer>
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
$(function () {
|
||||
// search form
|
||||
var form = jQuery("#search_form");
|
||||
|
||||
// we want to disable our submit button if we have no search text,
|
||||
// and we have no advanced options selected
|
||||
function toggleSubmit() {
|
||||
var nameSearch = $.trim($("#id_name").val());
|
||||
|
||||
var noAdvanced = true;
|
||||
function anyAdvancedActive() {
|
||||
var advanced = false;
|
||||
|
||||
var by = form.find("input[name=by]:checked");
|
||||
if (by.length > 0)
|
||||
by.closest(".search_field").find("input,select").not("input[name=by]").each(function () {
|
||||
if ($.trim(this.value))
|
||||
noAdvanced = false;
|
||||
advanced = true;
|
||||
});
|
||||
|
||||
form.find("input[type=submit]").get(0).disabled = !nameSearch && noAdvanced;
|
||||
return advanced;
|
||||
}
|
||||
|
||||
function toggleSubmit() {
|
||||
var nameSearch = $.trim($("#id_name").val());
|
||||
form.find("input[type=submit]").get(0).disabled = !nameSearch && !anyAdvancedActive();
|
||||
}
|
||||
|
||||
function togglePlusMinus(toggler, toggled) {
|
||||
|
@ -29,7 +31,7 @@ $(function () {
|
|||
}
|
||||
}
|
||||
|
||||
function updateBy() {
|
||||
function updateAdvanced() {
|
||||
form.find("input[name=by]:checked").closest(".search_field").find("input,select").not("input[name=by]").each(function () {
|
||||
this.disabled = false;
|
||||
});
|
||||
|
@ -41,25 +43,24 @@ $(function () {
|
|||
toggleSubmit();
|
||||
}
|
||||
|
||||
form.find(".search_field input[name=by]").closest("label").click(updateBy);
|
||||
if (form.length > 0) {
|
||||
form.find(".search_field input[name=by]").closest("label").click(updateAdvanced);
|
||||
|
||||
form.find(".search_field input,select")
|
||||
.change(toggleSubmit).click(toggleSubmit).keyup(toggleSubmit);
|
||||
form.find(".search_field input,select")
|
||||
.change(toggleSubmit).click(toggleSubmit).keyup(toggleSubmit);
|
||||
|
||||
form.find(".toggle_advanced").click(function () {
|
||||
var advanced = $(this).next();
|
||||
advanced.find('.search_field input[type="radio"]').attr("checked", false);
|
||||
togglePlusMinus($(this), advanced);
|
||||
updateBy();
|
||||
});
|
||||
form.find(".toggle_advanced").click(function () {
|
||||
var advanced = $(this).next();
|
||||
advanced.find('.search_field input[type="radio"]').attr("checked", false);
|
||||
togglePlusMinus($(this), advanced);
|
||||
updateAdvanced();
|
||||
});
|
||||
|
||||
updateBy();
|
||||
updateAdvanced();
|
||||
}
|
||||
|
||||
$("#search_results th").click(function (e) {
|
||||
window.location = $(this).find("a").attr("href");
|
||||
})
|
||||
|
||||
$('#search_results .addtolist a').click(function(e) {
|
||||
// search results
|
||||
$('.search-results .addtolist a').click(function(e) {
|
||||
e.preventDefault();
|
||||
var trigger = $(this);
|
||||
$.ajax({
|
||||
|
@ -74,4 +75,27 @@ $(function () {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("a.ballot-icon").click(function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
url: $(this).data("popup"),
|
||||
success: function (data) {
|
||||
showModalBox(data);
|
||||
},
|
||||
error: function () {
|
||||
showModalBox("<div>Error retrieving popup content</div>");
|
||||
}
|
||||
});
|
||||
}).each(function () {
|
||||
// bind right-click shortcut
|
||||
var editPositionUrl = $(this).data("edit");
|
||||
if (editPositionUrl) {
|
||||
$(this).bind("contextmenu", function (e) {
|
||||
e.preventDefault();
|
||||
window.location = editPositionUrl;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
jQuery(function () {
|
||||
jQuery("table.history .snippet .showAll").click(function () {
|
||||
jQuery("table.history .snippet .show-all").click(function () {
|
||||
jQuery(this).parents(".snippet").hide().siblings(".full").show();
|
||||
});
|
||||
});
|
||||
|
|
43
static/js/utils.js
Normal file
43
static/js/utils.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
function showModalBox(content, callback) {
|
||||
content = $(content);
|
||||
|
||||
// make sure previous one is gone
|
||||
$("#modal-overlay").remove();
|
||||
|
||||
// the url(data:...) part is backwards compatibility for non-rgba
|
||||
// supporting browsers (IE 8) - it's a 2 pixel black PNG with
|
||||
// opacity 50%
|
||||
var overlay = $('<div id="modal-overlay" style="position:fixed;z-index:100;top:0;left:0;height:100%;width:100%;background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAQAAABeK7cBAAAACXBIWXMAAAsTAAALEwEAmpwYAAAADUlEQVQIHWNgqGeoBwACAQD/+EjsGgAAAABJRU5ErkJggg==);background:rgba(0,0,0,0.5);"></div>');
|
||||
var box = $('<div id="modal-box" style="position:absolute;left:50%;top:50%"></div>');
|
||||
|
||||
box.append(content);
|
||||
overlay.append(box);
|
||||
|
||||
box.click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
overlay.click(closeModalBox);
|
||||
box.find(".button.close").click(function (e) {
|
||||
e.preventDefault();
|
||||
closeModalBox();
|
||||
});
|
||||
overlay.keydown(function (e) {
|
||||
if (e.which == 27)
|
||||
closeModalBox();
|
||||
});
|
||||
|
||||
$("body").append(overlay);
|
||||
|
||||
var w = content.outerWidth() || 400;
|
||||
var h = content.outerHeight() || 300;
|
||||
box.css({ "margin-left": -parseInt(w/2), "margin-top": -parseInt(h/2) });
|
||||
|
||||
content.focus();
|
||||
|
||||
if (callback)
|
||||
callback();
|
||||
}
|
||||
|
||||
function closeModalBox() {
|
||||
$("#modal-overlay").remove();
|
||||
}
|
Loading…
Reference in a new issue