diff --git a/src/rest/resource.py b/src/rest/resource.py index 18421a19c..4e9c4e053 100644 --- a/src/rest/resource.py +++ b/src/rest/resource.py @@ -1,6 +1,8 @@ from django.http import HttpResponse -from decimal import Decimal +from django.core.urlresolvers import reverse from rest import emitters, parsers +from decimal import Decimal + class Resource(object): @@ -29,6 +31,7 @@ class Resource(object): def __new__(cls, request, *args, **kwargs): self = object.__new__(cls) self.__init__() + self._request = request return self._handle_request(request, *args, **kwargs) def __init__(self): @@ -145,3 +148,8 @@ class Resource(object): def delete(self, headers={}, *args, **kwargs): return self._not_implemented('delete') + + def reverse(self, view, *args, **kwargs): + """Return a fully qualified URI for a view, using the current request as the base URI. + """ + return self._request.build_absolute_uri(reverse(view, *args, **kwargs)) diff --git a/src/rest/templates/emitter.html b/src/rest/templates/emitter.html index 4c843aa34..b3a2d8234 100644 --- a/src/rest/templates/emitter.html +++ b/src/rest/templates/emitter.html @@ -1,11 +1,18 @@ - +{% load urlize_quoted_links %} + + +

{{ resource_name }}

{{ resource_doc }}

-
-{% include 'emitter.txt' %}    
+
{% autoescape off %}HTTP Status {{ status }}
+{% for key, val in headers.items %}{{ key }}: {{ val }}
+{% endfor %}
+{{ content|urlize_quoted_links }}{% endautoescape %}    
\ No newline at end of file diff --git a/src/rest/templatetags/__init__.py b/src/rest/templatetags/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/rest/templatetags/__init__.pyc b/src/rest/templatetags/__init__.pyc new file mode 100644 index 000000000..69527f63d Binary files /dev/null and b/src/rest/templatetags/__init__.pyc differ diff --git a/src/rest/templatetags/urlize_quoted_links.py b/src/rest/templatetags/urlize_quoted_links.py new file mode 100644 index 000000000..cef179bf1 --- /dev/null +++ b/src/rest/templatetags/urlize_quoted_links.py @@ -0,0 +1,96 @@ +"""Adds the custom filter 'urlize_quoted_links' + +This is identical to the built-in filter 'urlize' with the exception that +single and double quotes are permitted as leading or trailing punctuation. +""" + +# Almost all of this code is copied verbatim from django.utils.html +# LEADING_PUNCTUATION and TRAILING_PUNCTUATION have been modified +import re +import string + +from django.utils.safestring import SafeData, mark_safe +from django.utils.encoding import force_unicode +from django.utils.http import urlquote +from django.utils.html import escape +from django import template + +# Configuration for urlize() function. +LEADING_PUNCTUATION = ['(', '<', '<', '"', "'"] +TRAILING_PUNCTUATION = ['.', ',', ')', '>', '\n', '>', '"', "'"] + +# List of possible strings used for bullets in bulleted lists. +DOTS = ['·', '*', '\xe2\x80\xa2', '•', '•', '•'] + +unencoded_ampersands_re = re.compile(r'&(?!(\w+|#\d+);)') +word_split_re = re.compile(r'(\s+)') +punctuation_re = re.compile('^(?P(?:%s)*)(?P.*?)(?P(?:%s)*)$' % \ + ('|'.join([re.escape(x) for x in LEADING_PUNCTUATION]), + '|'.join([re.escape(x) for x in TRAILING_PUNCTUATION]))) +simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$') +link_target_attribute_re = re.compile(r'(]*?)target=[^\s>]+') +html_gunk_re = re.compile(r'(?:
|<\/i>|<\/b>|<\/em>|<\/strong>|<\/?smallcaps>|<\/?uppercase>)', re.IGNORECASE) +hard_coded_bullets_re = re.compile(r'((?:

(?:%s).*?[a-zA-Z].*?

\s*)+)' % '|'.join([re.escape(x) for x in DOTS]), re.DOTALL) +trailing_empty_content_re = re.compile(r'(?:

(?: |\s|
)*?

\s*)+\Z') + +def urlize_quoted_links(text, trim_url_limit=None, nofollow=False, autoescape=False): + """ + Converts any URLs in text into clickable links. + + Works on http://, https://, www. links and links ending in .org, .net or + .com. Links can have trailing punctuation (periods, commas, close-parens) + and leading punctuation (opening parens) and it'll still do the right + thing. + + If trim_url_limit is not None, the URLs in link text longer than this limit + will truncated to trim_url_limit-3 characters and appended with an elipsis. + + If nofollow is True, the URLs in link text will get a rel="nofollow" + attribute. + + If autoescape is True, the link text and URLs will get autoescaped. + """ + trim_url = lambda x, limit=trim_url_limit: limit is not None and (len(x) > limit and ('%s...' % x[:max(0, limit - 3)])) or x + safe_input = isinstance(text, SafeData) + words = word_split_re.split(force_unicode(text)) + nofollow_attr = nofollow and ' rel="nofollow"' or '' + for i, word in enumerate(words): + match = None + if '.' in word or '@' in word or ':' in word: + match = punctuation_re.match(word) + if match: + lead, middle, trail = match.groups() + # Make URL we want to point to. + url = None + if middle.startswith('http://') or middle.startswith('https://'): + url = urlquote(middle, safe='/&=:;#?+*') + elif middle.startswith('www.') or ('@' not in middle and \ + middle and middle[0] in string.ascii_letters + string.digits and \ + (middle.endswith('.org') or middle.endswith('.net') or middle.endswith('.com'))): + url = urlquote('http://%s' % middle, safe='/&=:;#?+*') + elif '@' in middle and not ':' in middle and simple_email_re.match(middle): + url = 'mailto:%s' % middle + nofollow_attr = '' + # Make link. + if url: + trimmed = trim_url(middle) + if autoescape and not safe_input: + lead, trail = escape(lead), escape(trail) + url, trimmed = escape(url), escape(trimmed) + middle = '
%s' % (url, nofollow_attr, trimmed) + words[i] = mark_safe('%s%s%s' % (lead, middle, trail)) + else: + if safe_input: + words[i] = mark_safe(word) + elif autoescape: + words[i] = escape(word) + elif safe_input: + words[i] = mark_safe(word) + elif autoescape: + words[i] = escape(word) + return u''.join(words) + +# Register urlize_quoted_links as a custom filter +# http://docs.djangoproject.com/en/dev/howto/custom-template-tags/ +register = template.Library() +register.filter(urlize_quoted_links) \ No newline at end of file diff --git a/src/rest/templatetags/urlize_quoted_links.pyc b/src/rest/templatetags/urlize_quoted_links.pyc new file mode 100644 index 000000000..b49e16b67 Binary files /dev/null and b/src/rest/templatetags/urlize_quoted_links.pyc differ diff --git a/src/testapp/urls.py b/src/testapp/urls.py index a41c156bc..a7d430bc3 100644 --- a/src/testapp/urls.py +++ b/src/testapp/urls.py @@ -1,8 +1,7 @@ from django.conf.urls.defaults import patterns -from testapp.views import ReadOnlyResource, MirroringWriteResource - -urlpatterns = patterns('', - (r'^read-only$', ReadOnlyResource), - (r'^mirroring-write$', MirroringWriteResource), +urlpatterns = patterns('testapp.views', + (r'^$', 'RootResource'), + (r'^read-only$', 'ReadOnlyResource'), + (r'^mirroring-write$', 'MirroringWriteResource'), ) diff --git a/src/testapp/views.py b/src/testapp/views.py index f0174414b..eca4c0ae8 100644 --- a/src/testapp/views.py +++ b/src/testapp/views.py @@ -1,6 +1,15 @@ -from decimal import Decimal from rest.resource import Resource +class RootResource(Resource): + """This is my docstring + """ + allowed_methods = ('GET',) + + def read(self, headers={}, *args, **kwargs): + return (200, {'read-only-api': self.reverse(ReadOnlyResource), + 'write-only-api': self.reverse(MirroringWriteResource)}, {}) + + class ReadOnlyResource(Resource): """This is my docstring """ diff --git a/src/urls.py b/src/urls.py index f95e9afa4..41a32efa9 100644 --- a/src/urls.py +++ b/src/urls.py @@ -5,7 +5,7 @@ admin.autodiscover() urlpatterns = patterns('', # Example: - (r'^testapp/', include('testapp.urls')), + (r'^', include('testapp.urls')), # Uncomment the admin/doc line below to enable admin documentation: (r'^admin/doc/', include('django.contrib.admindocs.urls')),