diff --git a/ietf/idrfc/idrfc_wrapper.py b/ietf/idrfc/idrfc_wrapper.py index 66dab69ce..6d672f738 100644 --- a/ietf/idrfc/idrfc_wrapper.py +++ b/ietf/idrfc/idrfc_wrapper.py @@ -38,6 +38,8 @@ import re from datetime import date from django.utils import simplejson as json from django.db.models import Q +from django.db import models +from django.core.urlresolvers import reverse import types BALLOT_ACTIVE_STATES = ['In Last Call', @@ -198,11 +200,11 @@ class IdWrapper: def friendly_state(self): if self.draft_status == "RFC": - return "RFC %d" % (self.rfc_number, self.rfc_number) + return "RFC %d" % (reverse('doc_view', args=['rfc%d' % self.rfc_number]), self.rfc_number) elif self.draft_status == "Replaced": rs = self.replaced_by() if rs: - return "Replaced by %s" % (rs[0],rs[0]) + return "Replaced by %s" % (reverse('ipr_show', args=[rs[0]]),rs[0]) else: return "Replaced" elif self.draft_status == "Active": @@ -357,8 +359,9 @@ class RfcWrapper: # TODO: get AD name of the draft return None + @models.permalink def get_absolute_url(self): - return "/doc/rfc%d/" % (self.rfc_number,) + return ('ietf.idrfc.views_doc.document_main', ['rfc%s' % (str(self.rfc_number))]) def displayname_with_link(self): return 'RFC %d' % (self.get_absolute_url(), self.rfc_number) diff --git a/ietf/idrfc/views_doc.py b/ietf/idrfc/views_doc.py index 166467bc1..fc7b0d3e8 100644 --- a/ietf/idrfc/views_doc.py +++ b/ietf/idrfc/views_doc.py @@ -41,6 +41,7 @@ from django.template.defaultfilters import truncatewords_html from django.utils import simplejson as json from django.utils.decorators import decorator_from_middleware from django.middleware.gzip import GZipMiddleware +from django.core.urlresolvers import reverse from ietf import settings from ietf.idtracker.models import InternetDraft, IDInternal, BallotInfo, DocumentComment @@ -189,7 +190,7 @@ def _get_history(doc, versions): results.append({'is_text':True, 'date':doc._draft.expiration_date, 'text':'Draft expired'}) if doc.is_rfc_wrapper: if doc.draft_name: - text = 'RFC Published (see %s for earlier history)' % (doc.draft_name,doc.draft_name) + text = 'RFC Published (see %s for earlier history)' % (reverse('doc_view', args=[doc.draft_name]),doc.draft_name) else: text = 'RFC Published' results.append({'is_text':True, 'date':doc.publication_date, 'text':text}) diff --git a/ietf/ipr/feeds.py b/ietf/ipr/feeds.py index 476272768..4a1900302 100644 --- a/ietf/ipr/feeds.py +++ b/ietf/ipr/feeds.py @@ -3,12 +3,13 @@ from django.contrib.syndication.feeds import Feed from django.utils.feedgenerator import Atom1Feed from ietf.ipr.models import IprDetail +from ietf.utils.lazy import reverse_lazy from datetime import datetime, time class LatestIprDisclosures(Feed): feed_type = Atom1Feed title = "IPR Disclosures to the IETF" - link = "/ipr/" + link = reverse_lazy('ipr_showlist') description = "Updates on new IPR Disclosures made to the IETF." language = "en" feed_url = "/feed/ipr/" diff --git a/ietf/ipr/models.py b/ietf/ipr/models.py index d25d78193..456f49af4 100644 --- a/ietf/ipr/models.py +++ b/ietf/ipr/models.py @@ -4,6 +4,7 @@ from django.db import models #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 # ------------------------------------------------------------------------ # Models @@ -115,8 +116,9 @@ class IprDetail(models.Model): return self.title def docs(self): return list(self.drafts.all()) + list(self.rfcs.all()) + @models.permalink def get_absolute_url(self): - return "/ipr/%d/" % self.ipr_id + return ('ietf.ipr.views.show', [str(self.ipr_id)]) def get_submitter(self): try: return self.contact.get(contact_type=3) diff --git a/ietf/ipr/urls.py b/ietf/ipr/urls.py index 1e952d6b6..77a00f9a1 100644 --- a/ietf/ipr/urls.py +++ b/ietf/ipr/urls.py @@ -1,15 +1,16 @@ # Copyright The IETF Trust 2007, All Rights Reserved -from django.conf.urls.defaults import patterns +from django.conf.urls.defaults import patterns, url from ietf.ipr import views, new, search +from ietf.utils.lazy import reverse_lazy from django.views.generic.simple import redirect_to urlpatterns = patterns('', - (r'^$', views.showlist), + url(r'^$', views.showlist, name='ipr_showlist'), (r'^about/$', views.default), (r'^by-draft/$', views.list_drafts), - (r'^(?P\d+)/$', views.show), - (r'^update/$', redirect_to, { 'url': '/ipr/' }), + url(r'^(?P\d+)/$', views.show, name='ipr_show'), + (r'^update/$', redirect_to, { 'url': reverse_lazy('ipr_showlist') }), (r'^update/(?P\d+)/$', new.update), (r'^new-(?Pspecific)/$', new.new), (r'^new-(?Pgeneric)/$', new.new), diff --git a/ietf/utils/lazy.py b/ietf/utils/lazy.py new file mode 100644 index 000000000..dd31bd06c --- /dev/null +++ b/ietf/utils/lazy.py @@ -0,0 +1,20 @@ +from django.utils.functional import lazy +from django.core.urlresolvers import reverse + +""" +A lazily evaluated version of `reverse()`_. + +It is useful for when you need to use a URL reversal before Django's +URL names map is loaded. Some common cases where this method is necessary are: + + * in your URL configuration (such as the ``url`` argument for the + ``django.views.generic.simple.redirect_to`` generic view). + + * providing a reversed URL to a decorator (such as the ``login_url`` argument + for the ``django.contrib.auth.decorators.permission_required`` decorator). + +Usually unicode would be preference but str is the right type instead of unicode. +This is because reverse passes through iri_to_uri which converts it to a string +""" + +reverse_lazy = lazy(reverse, str) diff --git a/ietf/utils/test_utils.py b/ietf/utils/test_utils.py index 14461faf2..3e70a531b 100644 --- a/ietf/utils/test_utils.py +++ b/ietf/utils/test_utils.py @@ -215,3 +215,7 @@ def login_testing_unauthorized(tc, remote_user, url): tc.client.login(remote_user=remote_user) +class ReverseLazyTest(TestCase): + def test_redirect_with_lazy_reverse(self): + response = self.client.get('/ipr/update/') + self.assertRedirects(response, "/ipr/", status_code=301)