aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2014-09-05 09:07:14 +0100
committerTom Christie2014-09-05 09:07:14 +0100
commit2e632e5af221e8f9a29ce03f817013f79172b687 (patch)
treeb17df634e30017cf41720e969c4dabe81ebd25b5
parent29bcce70135d9fccd8d27a5e425f756363e28700 (diff)
parentef1fb3d8df8227961e3b24d1955af93be13519ea (diff)
downloaddjango-rest-framework-2e632e5af221e8f9a29ce03f817013f79172b687.tar.bz2
Merge pull request #1820 from carltongibson/login-dropdown
Hide login link in browsable API if the login view is not registered.
-rw-r--r--rest_framework/templates/rest_framework/base.html28
-rw-r--r--rest_framework/templatetags/rest_framework.py21
-rw-r--r--tests/browsable_api/__init__.py0
-rw-r--r--tests/browsable_api/auth_urls.py10
-rw-r--r--tests/browsable_api/no_auth_urls.py9
-rw-r--r--tests/browsable_api/test_browsable_api.py65
-rw-r--r--tests/browsable_api/views.py15
7 files changed, 124 insertions, 24 deletions
diff --git a/rest_framework/templates/rest_framework/base.html b/rest_framework/templates/rest_framework/base.html
index e54e3814..a84ccf26 100644
--- a/rest_framework/templates/rest_framework/base.html
+++ b/rest_framework/templates/rest_framework/base.html
@@ -5,14 +5,14 @@
<html>
<head>
{% block head %}
-
+
{% block meta %}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="robots" content="NONE,NOARCHIVE" />
{% endblock %}
-
+
<title>{% block title %}Django REST framework{% endblock %}</title>
-
+
{% block style %}
{% block bootstrap_theme %}
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/>
@@ -21,7 +21,7 @@
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/prettify.css" %}"/>
<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/default.css" %}"/>
{% endblock %}
-
+
{% endblock %}
</head>
@@ -44,17 +44,9 @@
<ul class="nav pull-right">
{% block userlinks %}
{% if user.is_authenticated %}
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown">
- {{ user }}
- <b class="caret"></b>
- </a>
- <ul class="dropdown-menu">
- <li>{% optional_logout request %}</li>
- </ul>
- </li>
+ {% optional_logout request user %}
{% else %}
- <li>{% optional_login request %}</li>
+ {% optional_login request %}
{% endif %}
{% endblock %}
</ul>
@@ -85,7 +77,7 @@
<div class="btn-group format-selection">
<a class="btn btn-primary js-tooltip" href='{{ request.get_full_path }}'
rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a>
-
+
<button class="btn btn-primary dropdown-toggle js-tooltip" data-toggle="dropdown"
title="Specify a format for the GET request">
<span class="caret"></span>
@@ -144,7 +136,7 @@
</div>
{% if display_edit_forms %}
-
+
{% if post_form or raw_data_post_form %}
<div {% if post_form %}class="tabbable"{% endif %}>
{% if post_form %}
@@ -190,7 +182,7 @@
</div>
</div>
{% endif %}
-
+
{% if put_form or raw_data_put_form or raw_data_patch_form %}
<div {% if put_form %}class="tabbable"{% endif %}>
{% if put_form %}
@@ -246,7 +238,7 @@
{% endif %}
</div>
<!-- END Content -->
-
+
<footer>
{% block footer %}
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</p>
diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py
index b80a7d77..864d64dd 100644
--- a/rest_framework/templatetags/rest_framework.py
+++ b/rest_framework/templatetags/rest_framework.py
@@ -41,22 +41,31 @@ def optional_login(request):
except NoReverseMatch:
return ''
- snippet = "<a href='%s?next=%s'>Log in</a>" % (login_url, escape(request.path))
+ snippet = "<li><a href='{href}?next={next}'>Log in</a></li>".format(href=login_url, next=escape(request.path))
return snippet
@register.simple_tag
-def optional_logout(request):
+def optional_logout(request, user):
"""
Include a logout snippet if REST framework's logout view is in the URLconf.
"""
try:
logout_url = reverse('rest_framework:logout')
except NoReverseMatch:
- return ''
-
- snippet = "<a href='%s?next=%s'>Log out</a>" % (logout_url, escape(request.path))
- return snippet
+ return '<li class="navbar-text">{user}</li>'.format(user=user)
+
+ snippet = """<li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">
+ {user}
+ <b class="caret"></b>
+ </a>
+ <ul class="dropdown-menu">
+ <li><a href='{href}?next={next}'>Log out</a></li>
+ </ul>
+ </li>"""
+
+ return snippet.format(user=user, href=logout_url, next=escape(request.path))
@register.simple_tag
diff --git a/tests/browsable_api/__init__.py b/tests/browsable_api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/browsable_api/__init__.py
diff --git a/tests/browsable_api/auth_urls.py b/tests/browsable_api/auth_urls.py
new file mode 100644
index 00000000..bce7dcf9
--- /dev/null
+++ b/tests/browsable_api/auth_urls.py
@@ -0,0 +1,10 @@
+from __future__ import unicode_literals
+from django.conf.urls import patterns, url, include
+
+from .views import MockView
+
+urlpatterns = patterns(
+ '',
+ (r'^$', MockView.as_view()),
+ url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
+)
diff --git a/tests/browsable_api/no_auth_urls.py b/tests/browsable_api/no_auth_urls.py
new file mode 100644
index 00000000..5e3604a6
--- /dev/null
+++ b/tests/browsable_api/no_auth_urls.py
@@ -0,0 +1,9 @@
+from __future__ import unicode_literals
+from django.conf.urls import patterns
+
+from .views import MockView
+
+urlpatterns = patterns(
+ '',
+ (r'^$', MockView.as_view()),
+)
diff --git a/tests/browsable_api/test_browsable_api.py b/tests/browsable_api/test_browsable_api.py
new file mode 100644
index 00000000..5f264783
--- /dev/null
+++ b/tests/browsable_api/test_browsable_api.py
@@ -0,0 +1,65 @@
+from __future__ import unicode_literals
+from django.contrib.auth.models import User
+from django.test import TestCase
+
+from rest_framework.test import APIClient
+
+
+class DropdownWithAuthTests(TestCase):
+ """Tests correct dropdown behaviour with Auth views enabled."""
+
+ urls = 'tests.browsable_api.auth_urls'
+
+ def setUp(self):
+ self.client = APIClient(enforce_csrf_checks=True)
+ self.username = 'john'
+ self.email = 'lennon@thebeatles.com'
+ self.password = 'password'
+ self.user = User.objects.create_user(self.username, self.email, self.password)
+
+ def tearDown(self):
+ self.client.logout()
+
+ def test_name_shown_when_logged_in(self):
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get('/')
+ self.assertContains(response, 'john')
+
+ def test_logout_shown_when_logged_in(self):
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get('/')
+ self.assertContains(response, '>Log out<')
+
+ def test_login_shown_when_logged_out(self):
+ response = self.client.get('/')
+ self.assertContains(response, '>Log in<')
+
+
+class NoDropdownWithoutAuthTests(TestCase):
+ """Tests correct dropdown behaviour with Auth views NOT enabled."""
+
+ urls = 'tests.browsable_api.no_auth_urls'
+
+ def setUp(self):
+ self.client = APIClient(enforce_csrf_checks=True)
+ self.username = 'john'
+ self.email = 'lennon@thebeatles.com'
+ self.password = 'password'
+ self.user = User.objects.create_user(self.username, self.email, self.password)
+
+ def tearDown(self):
+ self.client.logout()
+
+ def test_name_shown_when_logged_in(self):
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get('/')
+ self.assertContains(response, 'john')
+
+ def test_dropdown_not_shown_when_logged_in(self):
+ self.client.login(username=self.username, password=self.password)
+ response = self.client.get('/')
+ self.assertNotContains(response, '<li class="dropdown">')
+
+ def test_dropdown_not_shown_when_logged_out(self):
+ response = self.client.get('/')
+ self.assertNotContains(response, '<li class="dropdown">')
diff --git a/tests/browsable_api/views.py b/tests/browsable_api/views.py
new file mode 100644
index 00000000..000f4e80
--- /dev/null
+++ b/tests/browsable_api/views.py
@@ -0,0 +1,15 @@
+from __future__ import unicode_literals
+
+from rest_framework.views import APIView
+from rest_framework import authentication
+from rest_framework import renderers
+from rest_framework.response import Response
+
+
+class MockView(APIView):
+
+ authentication_classes = (authentication.SessionAuthentication,)
+ renderer_classes = (renderers.BrowsableAPIRenderer,)
+
+ def get(self, request):
+ return Response({'a': 1, 'b': 2, 'c': 3})