diff --git a/django/contrib/admindocs/middleware.py b/django/contrib/admindocs/middleware.py new file mode 100644 index 00000000000..ee3fe2cb2f7 --- /dev/null +++ b/django/contrib/admindocs/middleware.py @@ -0,0 +1,23 @@ +from django.conf import settings +from django import http + +class XViewMiddleware(object): + """ + Adds an X-View header to internal HEAD requests -- used by the documentation system. + """ + def process_view(self, request, view_func, view_args, view_kwargs): + """ + If the request method is HEAD and either the IP is internal or the + user is a logged-in staff member, quickly return with an x-header + indicating the view function. This is used by the documentation module + to lookup the view function for an arbitrary page. + """ + assert hasattr(request, 'user'), ( + "The XView middleware requires authentication middleware to be " + "installed. Edit your MIDDLEWARE_CLASSES setting to insert " + "'django.contrib.auth.middleware.AuthenticationMiddleware'.") + if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or + (request.user.is_active and request.user.is_staff)): + response = http.HttpResponse() + response['X-View'] = "%s.%s" % (view_func.__module__, view_func.__name__) + return response diff --git a/django/middleware/doc.py b/django/middleware/doc.py index ee3fe2cb2f7..1af7b6150ab 100644 --- a/django/middleware/doc.py +++ b/django/middleware/doc.py @@ -1,23 +1,6 @@ -from django.conf import settings -from django import http +"""XViewMiddleware has been moved to django.contrib.admindocs.middleware.""" -class XViewMiddleware(object): - """ - Adds an X-View header to internal HEAD requests -- used by the documentation system. - """ - def process_view(self, request, view_func, view_args, view_kwargs): - """ - If the request method is HEAD and either the IP is internal or the - user is a logged-in staff member, quickly return with an x-header - indicating the view function. This is used by the documentation module - to lookup the view function for an arbitrary page. - """ - assert hasattr(request, 'user'), ( - "The XView middleware requires authentication middleware to be " - "installed. Edit your MIDDLEWARE_CLASSES setting to insert " - "'django.contrib.auth.middleware.AuthenticationMiddleware'.") - if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or - (request.user.is_active and request.user.is_staff)): - response = http.HttpResponse() - response['X-View'] = "%s.%s" % (view_func.__module__, view_func.__name__) - return response +import warnings +warnings.warn(__doc__, PendingDeprecationWarning, stacklevel=2) + +from django.contrib.admindocs.middleware import XViewMiddleware diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt index 394d078e5bd..4af94bdcf6c 100644 --- a/docs/ref/contrib/admin/admindocs.txt +++ b/docs/ref/contrib/admin/admindocs.txt @@ -31,7 +31,7 @@ the following: * **Optional:** Linking to templates requires the :setting:`ADMIN_FOR` setting to be configured. * **Optional:** Using the admindocs bookmarklets requires the - :mod:`XViewMiddleware` to be installed. + :mod:`XViewMiddleware` to be installed. Once those steps are complete, you can start browsing the documentation by going to your admin interface and clicking the "Documentation" link in the @@ -156,7 +156,7 @@ Edit this object Using these bookmarklets requires that you are either logged into the :mod:`Django admin ` as a :class:`~django.contrib.auth.models.User` with -:attr:`~django.contrib.auth.models.User.is_staff` set to `True`, or -that the :mod:`django.middleware.doc` middleware and -:mod:`XViewMiddleware ` are installed and you -are accessing the site from an IP address listed in :setting:`INTERNAL_IPS`. +:attr:`~django.contrib.auth.models.User.is_staff` set to `True`, or that the +:mod:`XViewMiddleware ` is installed and +you are accessing the site from an IP address listed in +:setting:`INTERNAL_IPS`. diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index 03885a22154..4898bab6365 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -71,19 +71,6 @@ Adds a few conveniences for perfectionists: * Sends broken link notification emails to :setting:`MANAGERS` (see :doc:`/howto/error-reporting`). -View metadata middleware ------------------------- - -.. module:: django.middleware.doc - :synopsis: Middleware to help your app self-document. - -.. class:: XViewMiddleware - -Sends custom ``X-View`` HTTP headers to HEAD requests that come from IP -addresses defined in the :setting:`INTERNAL_IPS` setting. This is used by -Django's :doc:`automatic documentation system `. -Depends on :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`. - GZip middleware --------------- diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 8ef59064f73..c1170e19c55 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -1243,7 +1243,7 @@ Default: ``()`` (Empty tuple) A tuple of IP addresses, as strings, that: * See debug comments, when :setting:`DEBUG` is ``True`` -* Receive X headers if the ``XViewMiddleware`` is installed (see +* Receive X headers in admindocs if the ``XViewMiddleware`` is installed (see :doc:`/topics/http/middleware`) .. setting:: LANGUAGE_CODE diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt index b4668c38d04..6643fb7d32a 100644 --- a/docs/releases/1.6.txt +++ b/docs/releases/1.6.txt @@ -502,6 +502,10 @@ Miscellaneous ineffective so it has been removed, along with its generic implementation, previously available in ``django.core.xheaders``. +* The ``XViewMiddleware`` has been moved from ``django.middleware.doc`` to + ``django.contrib.admindocs.middleware`` because it is an implementation + detail of admindocs, proven not to be reusable in general. + Features deprecated in 1.6 ========================== diff --git a/tests/admin_docs/__init__.py b/tests/admin_docs/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/admin_docs/fixtures/data.xml b/tests/admin_docs/fixtures/data.xml new file mode 100644 index 00000000000..aba8f4aace8 --- /dev/null +++ b/tests/admin_docs/fixtures/data.xml @@ -0,0 +1,17 @@ + + + + super + Super + User + super@example.com + sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 + True + True + True + 2007-05-30 13:20:10 + 2007-05-30 13:20:10 + + + + diff --git a/tests/admin_docs/models.py b/tests/admin_docs/models.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/admin_docs/tests.py b/tests/admin_docs/tests.py new file mode 100644 index 00000000000..aeb527c7b97 --- /dev/null +++ b/tests/admin_docs/tests.py @@ -0,0 +1,45 @@ +from django.contrib.auth.models import User +from django.test import TestCase +from django.test.utils import override_settings + + +@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) +class XViewMiddlewareTest(TestCase): + fixtures = ['data.xml'] + urls = 'admin_docs.urls' + + def test_xview_func(self): + user = User.objects.get(username='super') + response = self.client.head('/xview/func/') + self.assertFalse('X-View' in response) + self.client.login(username='super', password='secret') + response = self.client.head('/xview/func/') + self.assertTrue('X-View' in response) + self.assertEqual(response['X-View'], 'admin_docs.views.xview') + user.is_staff = False + user.save() + response = self.client.head('/xview/func/') + self.assertFalse('X-View' in response) + user.is_staff = True + user.is_active = False + user.save() + response = self.client.head('/xview/func/') + self.assertFalse('X-View' in response) + + def test_xview_class(self): + user = User.objects.get(username='super') + response = self.client.head('/xview/class/') + self.assertFalse('X-View' in response) + self.client.login(username='super', password='secret') + response = self.client.head('/xview/class/') + self.assertTrue('X-View' in response) + self.assertEqual(response['X-View'], 'admin_docs.views.XViewClass') + user.is_staff = False + user.save() + response = self.client.head('/xview/class/') + self.assertFalse('X-View' in response) + user.is_staff = True + user.is_active = False + user.save() + response = self.client.head('/xview/class/') + self.assertFalse('X-View' in response) diff --git a/tests/admin_docs/urls.py b/tests/admin_docs/urls.py new file mode 100644 index 00000000000..3c3a8fe5d8f --- /dev/null +++ b/tests/admin_docs/urls.py @@ -0,0 +1,11 @@ +# coding: utf-8 +from __future__ import absolute_import + +from django.conf.urls import patterns + +from . import views + +urlpatterns = patterns('', + (r'^xview/func/$', views.xview_dec(views.xview)), + (r'^xview/class/$', views.xview_dec(views.XViewClass.as_view())), +) diff --git a/tests/admin_docs/views.py b/tests/admin_docs/views.py new file mode 100644 index 00000000000..e47177c37f8 --- /dev/null +++ b/tests/admin_docs/views.py @@ -0,0 +1,13 @@ +from django.http import HttpResponse +from django.utils.decorators import decorator_from_middleware +from django.views.generic import View +from django.contrib.admindocs.middleware import XViewMiddleware + +xview_dec = decorator_from_middleware(XViewMiddleware) + +def xview(request): + return HttpResponse() + +class XViewClass(View): + def get(self, request): + return HttpResponse()