Login/Logout and FlyWheel API link in HTML emitter

parent e227c38b
# Django settings for src project. # Django settings for src project.
import os
BASE_DIR = os.path.dirname(__file__)
DEBUG = True DEBUG = True
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
...@@ -81,6 +84,7 @@ TEMPLATE_DIRS = ( ...@@ -81,6 +84,7 @@ TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows. # Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths. # Don't forget to use absolute paths, not relative paths.
os.path.join(BASE_DIR, 'templates')
) )
INSTALLED_APPS = ( INSTALLED_APPS = (
......
...@@ -7,6 +7,8 @@ urlpatterns = patterns('', ...@@ -7,6 +7,8 @@ urlpatterns = patterns('',
(r'pygments-example/', include('pygments_api.urls')), (r'pygments-example/', include('pygments_api.urls')),
(r'^blog-post-example/', include('blogpost.urls')), (r'^blog-post-example/', include('blogpost.urls')),
(r'^object-store-example/', include('objectstore.urls')), (r'^object-store-example/', include('objectstore.urls')),
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
(r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
(r'^admin/doc/', include('django.contrib.admindocs.urls')), (r'^admin/doc/', include('django.contrib.admindocs.urls')),
(r'^admin/', include(admin.site.urls)), (r'^admin/', include(admin.site.urls)),
) )
from django.conf import settings
from django.template import RequestContext, loader from django.template import RequestContext, loader
from django import forms from django import forms
from flywheel.response import NoContent from flywheel.response import NoContent
from utils import dict2xml from utils import dict2xml, url_resolves
import string import string
try: try:
import json import json
...@@ -12,6 +13,7 @@ except ImportError: ...@@ -12,6 +13,7 @@ except ImportError:
class BaseEmitter(object): class BaseEmitter(object):
media_type = None media_type = None
...@@ -118,13 +120,22 @@ class DocumentingTemplateEmitter(BaseEmitter): ...@@ -118,13 +120,22 @@ class DocumentingTemplateEmitter(BaseEmitter):
content = self._get_content(self.resource, output) content = self._get_content(self.resource, output)
form_instance = self._get_form_instance(self.resource) form_instance = self._get_form_instance(self.resource)
if url_resolves(settings.LOGIN_URL) and url_resolves(settings.LOGOUT_URL):
login_url = "%s?next=%s" % (settings.LOGIN_URL, self.resource.request.path)
logout_url = "%s?next=%s" % (settings.LOGOUT_URL, self.resource.request.path)
else:
login_url = None
logout_url = None
template = loader.get_template(self.template) template = loader.get_template(self.template)
context = RequestContext(self.resource.request, { context = RequestContext(self.resource.request, {
'content': content, 'content': content,
'resource': self.resource, 'resource': self.resource,
'request': self.resource.request, 'request': self.resource.request,
'response': self.resource.response, 'response': self.resource.response,
'form': form_instance 'form': form_instance,
'login_url': login_url,
'logout_url': logout_url,
}) })
ret = template.render(context) ret = template.render(context)
......
...@@ -7,9 +7,7 @@ from flywheel.response import status, Response, ResponseException ...@@ -7,9 +7,7 @@ from flywheel.response import status, Response, ResponseException
from decimal import Decimal from decimal import Decimal
import re import re
from itertools import chain
# TODO: Display user login in top panel: http://stackoverflow.com/questions/806835/django-redirect-to-previous-page-after-login
# TODO: Figure how out references and named urls need to work nicely # TODO: Figure how out references and named urls need to work nicely
# TODO: POST on existing 404 URL, PUT on existing 404 URL # TODO: POST on existing 404 URL, PUT on existing 404 URL
# #
......
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
<head> <head>
<style> <style>
pre {border: 1px solid black; padding: 1em; background: #ffd} pre {border: 1px solid black; padding: 1em; background: #ffd}
body {margin: 0; border:0; padding: 0;}
span.api {margin: 0.5em 1em}
span.auth {float: right; margin-right: 1em}
div.header {margin: 0; border:0; padding: 0.25em 0; background: #ddf}
div.content {margin: 0 1em;}
div.action {border: 1px solid black; padding: 0.5em 1em; margin-bottom: 0.5em; background: #ddf} div.action {border: 1px solid black; padding: 0.5em 1em; margin-bottom: 0.5em; background: #ddf}
ul.accepttypes {float: right; list-style-type: none; margin: 0; padding: 0} ul.accepttypes {float: right; list-style-type: none; margin: 0; padding: 0}
ul.accepttypes li {display: inline;} ul.accepttypes li {display: inline;}
...@@ -17,82 +22,87 @@ ...@@ -17,82 +22,87 @@
<title>API - {{ resource.name }}</title> <title>API - {{ resource.name }}</title>
</head> </head>
<body> <body>
<h1>{{ resource.name }}</h1> <div class='header'>
<p>{{ resource.description|linebreaksbr }}</p> <span class='api'><a href='http://www.thewebhaswon.com/flywheel/'>FlyWheel API</a></span>
<pre><b>{{ response.status }} {{ response.status_text }}</b>{% autoescape off %} <span class='auth'>{% if user.is_active %}Welcome, {{ user }}.{% if logout_url %} <a href='{{ logout_url }}'>Log out</a>{% endif %}{% else %}Not logged in {% if login_url %}<a href='{{ login_url }}'>Log in</a>{% endif %}{% endif %}</span>
{% for key, val in response.headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
{% endfor %}
{{ content|urlize_quoted_links }} </pre>{% endautoescape %}
{% if 'GET' in resource.allowed_methods %}
<div class='action'>
<a href='{{ request.path }}'>GET</a>
<ul class="accepttypes">
{% for media_type in resource.emitted_media_types %}
{% with resource.ACCEPT_QUERY_PARAM|add:"="|add:media_type as param %}
<li>[<a href='{{ request.path|add_query_param:param }}'>{{ media_type }}</a>]</li>
{% endwith %}
{% endfor %}
</ul>
<div class="clearing"></div>
</div> </div>
{% endif %} <div class='content'>
<h1>{{ resource.name }}</h1>
{% comment %} *** Only display the POST/PUT/DELETE forms if we have a bound form, and if method *** <p>{{ resource.description|linebreaksbr }}</p>
*** tunneling via POST forms is enabled. *** <pre><b>{{ response.status }} {{ response.status_text }}</b>{% autoescape off %}
*** (We could display only the POST form if method tunneling is disabled, but I think *** {% for key, val in response.headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
*** the user experience would be confusing, so we simply turn all forms off. *** {% endcomment %} {% endfor %}
{{ content|urlize_quoted_links }}</pre>{% endautoescape %}
{% if resource.METHOD_PARAM and form %}
{% if 'POST' in resource.allowed_methods %}
<div class='action'>
<form action="{{ request.path }}" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
<div>
{{ field.label_tag }}:
{{ field }}
{{ field.help_text }}
{{ field.errors }}
</div>
{% endfor %}
<div class="clearing"></div>
<input type="submit" value="POST" />
</form>
</div>
{% endif %}
{% if 'PUT' in resource.allowed_methods %} {% if 'GET' in resource.allowed_methods %}
<div class='action'> <div class='action'>
<form action="{{ request.path }}" method="post"> <a href='{{ request.path }}'>GET</a>
<input type="hidden" name="{{ resource.METHOD_PARAM }}" value="PUT" /> <ul class="accepttypes">
{% csrf_token %} {% for media_type in resource.emitted_media_types %}
{{ form.non_field_errors }} {% with resource.ACCEPT_QUERY_PARAM|add:"="|add:media_type as param %}
{% for field in form %} <li>[<a href='{{ request.path|add_query_param:param }}'>{{ media_type }}</a>]</li>
<div> {% endwith %}
{{ field.label_tag }}: {% endfor %}
{{ field }} </ul>
{{ field.help_text }} <div class="clearing"></div>
{{ field.errors }}
</div>
{% endfor %}
<div class="clearing"></div>
<input type="submit" value="PUT" />
</form>
</div> </div>
{% endif %} {% endif %}
{% if 'DELETE' in resource.allowed_methods %} {% comment %} *** Only display the POST/PUT/DELETE forms if we have a bound form, and if method ***
<div class='action'> *** tunneling via POST forms is enabled. ***
<form action="{{ request.path }}" method="post"> *** (We could display only the POST form if method tunneling is disabled, but I think ***
{% csrf_token %} *** the user experience would be confusing, so we simply turn all forms off. *** {% endcomment %}
<input type="hidden" name="{{ resource.METHOD_PARAM }}" value="DELETE" />
<input type="submit" value="DELETE" /> {% if resource.METHOD_PARAM and form %}
</form> {% if 'POST' in resource.allowed_methods %}
</div> <div class='action'>
<form action="{{ request.path }}" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
<div>
{{ field.label_tag }}:
{{ field }}
{{ field.help_text }}
{{ field.errors }}
</div>
{% endfor %}
<div class="clearing"></div>
<input type="submit" value="POST" />
</form>
</div>
{% endif %}
{% if 'PUT' in resource.allowed_methods %}
<div class='action'>
<form action="{{ request.path }}" method="post">
<input type="hidden" name="{{ resource.METHOD_PARAM }}" value="PUT" />
{% csrf_token %}
{{ form.non_field_errors }}
{% for field in form %}
<div>
{{ field.label_tag }}:
{{ field }}
{{ field.help_text }}
{{ field.errors }}
</div>
{% endfor %}
<div class="clearing"></div>
<input type="submit" value="PUT" />
</form>
</div>
{% endif %}
{% if 'DELETE' in resource.allowed_methods %}
<div class='action'>
<form action="{{ request.path }}" method="post">
{% csrf_token %}
<input type="hidden" name="{{ resource.METHOD_PARAM }}" value="DELETE" />
<input type="submit" value="DELETE" />
</form>
</div>
{% endif %}
{% endif %} {% endif %}
{% endif %} </div>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -2,11 +2,21 @@ import re ...@@ -2,11 +2,21 @@ import re
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
from django.utils.xmlutils import SimplerXMLGenerator from django.utils.xmlutils import SimplerXMLGenerator
from django.core.urlresolvers import resolve
try: try:
import cStringIO as StringIO import cStringIO as StringIO
except ImportError: except ImportError:
import StringIO import StringIO
def url_resolves(url):
"""Return True if the given URL is mapped to a view in the urlconf, False otherwise."""
try:
resolve(url)
except:
return False
return True
# From piston # From piston
def coerce_put_post(request): def coerce_put_post(request):
""" """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment