Skip to content

Commit

Permalink
Fixed #20126 -- XViewMiddleware moved to django.contrib.admindocs.mid…
Browse files Browse the repository at this point in the history
…dleware
  • Loading branch information
ambv committed May 19, 2013
1 parent a7e2835 commit 6607626
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 41 deletions.
23 changes: 23 additions & 0 deletions 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
27 changes: 5 additions & 22 deletions 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
10 changes: 5 additions & 5 deletions docs/ref/contrib/admin/admindocs.txt
Expand Up @@ -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<django.middleware.doc>` to be installed.
:mod:`XViewMiddleware<django.contrib.admindocs.middleware>` 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
Expand Down Expand Up @@ -156,7 +156,7 @@ Edit this object
Using these bookmarklets requires that you are either logged into the
:mod:`Django admin <django.contrib.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 <django.middleware.doc>` 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 <django.contrib.admindocs.middleware>` is installed and
you are accessing the site from an IP address listed in
:setting:`INTERNAL_IPS`.
13 changes: 0 additions & 13 deletions docs/ref/middleware.txt
Expand Up @@ -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 </ref/contrib/admin/admindocs>`.
Depends on :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`.

GZip middleware
---------------

Expand Down
2 changes: 1 addition & 1 deletion docs/ref/settings.txt
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions docs/releases/1.6.txt
Expand Up @@ -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
==========================

Expand Down
Empty file added tests/admin_docs/__init__.py
Empty file.
17 changes: 17 additions & 0 deletions tests/admin_docs/fixtures/data.xml
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="100" model="auth.user">
<field type="CharField" name="username">super</field>
<field type="CharField" name="first_name">Super</field>
<field type="CharField" name="last_name">User</field>
<field type="CharField" name="email">super@example.com</field>
<field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field>
<field type="BooleanField" name="is_staff">True</field>
<field type="BooleanField" name="is_active">True</field>
<field type="BooleanField" name="is_superuser">True</field>
<field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
<field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
<field to="auth.group" name="groups" rel="ManyToManyRel"></field>
<field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
</object>
</django-objects>
Empty file added tests/admin_docs/models.py
Empty file.
45 changes: 45 additions & 0 deletions 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)
11 changes: 11 additions & 0 deletions 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())),
)
13 changes: 13 additions & 0 deletions 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()

0 comments on commit 6607626

Please sign in to comment.