kopia lustrzana https://github.com/wagtail/wagtail
Page.dummy_request() now takes an optional request object argument.
When building a dummy request, you can now pass in the original request object to add additional information to the dummy. Currently, that includes the following headers: REMOTE_ADDR HTTP_X_FORWARDED_FOR HTTP_COOKIE HTTP_USER_AGENT More may be added later. This changes ensures that middleware which work on the client IP aren't flumuxed by its absense, and also makes it possible for previews to be rendered as the logged in user (they had previously been rendered using an AnnonymousUser). Because the user's logged in state is now detectable in a Page previews, the Wagtail userbar now hides itself explicitly during previews, rather than relying on the fact that previews used to be built with AnonymousUser.pull/2829/head
rodzic
14919f3b41
commit
cbabc3d9c7
|
@ -22,6 +22,7 @@ Changelog
|
|||
* `wagtailforms.models.AbstractEmailForm` now supports multiple email recipients (Serafeim Papastefanos)
|
||||
* Added the ``include_block`` template tag for improved StreamField template inclusion (Matt Westcott)
|
||||
* Added ability to delete users through Settings -> Users (Vincent Audebert; thanks also to Ludolf Takens and Tobias Schmidt for alternative implementations)
|
||||
* Page previews now pass additional HTTP headers, to simulate the page being viewed by the logged-in user and avoid clashes with middleware (Robert Rollins)
|
||||
* Fix: Email templates and document uploader now support custom `STATICFILES_STORAGE` (Jonny Scholes)
|
||||
* Fix: Removed alignment options (deprecated in HTML and not rendered by Wagtail) from `TableBlock` context menu (Moritz Pfeiffer)
|
||||
* Fix: Fixed incorrect CSS path on ModelAdmin's "choose a parent page" view
|
||||
|
|
|
@ -37,6 +37,7 @@ Minor features
|
|||
* ``wagtailforms.models.AbstractEmailForm`` now supports multiple email recipients (Serafeim Papastefanos)
|
||||
* Added the ``include_block`` template tag for improved StreamField template inclusion. See :doc:`/topics/streamfield` for documentation (Matt Westcott)
|
||||
* Added ability to delete users through Settings -> Users (Vincent Audebert; thanks also to Ludolf Takens and Tobias Schmidt for alternative implementations)
|
||||
* Page previews now pass additional HTTP headers, to simulate the page being viewed by the logged-in user and avoid clashes with middleware (Robert Rollins)
|
||||
|
||||
|
||||
Bug fixes
|
||||
|
|
|
@ -40,6 +40,11 @@ def wagtailuserbar(context, position='bottom-right'):
|
|||
if not request.user.has_perm('wagtailadmin.access_admin'):
|
||||
return ''
|
||||
|
||||
# Don't render if this is a preview. Since some routes can render the userbar without going through Page.serve(),
|
||||
# request.is_preview might not be defined.
|
||||
if getattr(request, 'is_preview', False):
|
||||
return ''
|
||||
|
||||
# Only render if the context contains a variable referencing a saved page
|
||||
page = get_page_instance(context)
|
||||
if page is None:
|
||||
|
|
|
@ -496,7 +496,7 @@ def delete(request, page_id):
|
|||
|
||||
def view_draft(request, page_id):
|
||||
page = get_object_or_404(Page, id=page_id).get_latest_revision_as_page()
|
||||
return page.serve_preview(page.dummy_request(), page.default_preview_mode)
|
||||
return page.serve_preview(page.dummy_request(request), page.default_preview_mode)
|
||||
|
||||
|
||||
def preview_on_edit(request, page_id):
|
||||
|
@ -516,7 +516,7 @@ def preview_on_edit(request, page_id):
|
|||
page.full_clean()
|
||||
|
||||
preview_mode = request.GET.get('mode', page.default_preview_mode)
|
||||
response = page.serve_preview(page.dummy_request(), preview_mode)
|
||||
response = page.serve_preview(page.dummy_request(request), preview_mode)
|
||||
response['X-Wagtail-Preview'] = 'ok'
|
||||
return response
|
||||
|
||||
|
@ -576,7 +576,7 @@ def preview_on_create(request, content_type_app_name, content_type_model_name, p
|
|||
page.path = Page._get_children_path_interval(parent_page.path)[1]
|
||||
|
||||
preview_mode = request.GET.get('mode', page.default_preview_mode)
|
||||
response = page.serve_preview(page.dummy_request(), preview_mode)
|
||||
response = page.serve_preview(page.dummy_request(request), preview_mode)
|
||||
response['X-Wagtail-Preview'] = 'ok'
|
||||
return response
|
||||
|
||||
|
@ -1013,4 +1013,4 @@ def revisions_view(request, page_id, revision_id):
|
|||
revision = get_object_or_404(page.revisions, id=revision_id)
|
||||
revision_page = revision.as_page_object()
|
||||
|
||||
return revision_page.serve_preview(page.dummy_request(), page.default_preview_mode)
|
||||
return revision_page.serve_preview(page.dummy_request(request), page.default_preview_mode)
|
||||
|
|
|
@ -1168,12 +1168,15 @@ class Page(six.with_metaclass(PageBase, MP_Node, index.Indexed, ClusterableModel
|
|||
user_perms = UserPagePermissionsProxy(user)
|
||||
return user_perms.for_page(self)
|
||||
|
||||
def dummy_request(self):
|
||||
def dummy_request(self, original_request=None, **meta):
|
||||
"""
|
||||
Construct a HttpRequest object that is, as far as possible, representative of ones that would
|
||||
receive this page as a response. Used for previewing / moderation and any other place where we
|
||||
want to display a view of this page in the admin interface without going through the regular
|
||||
page routing logic.
|
||||
|
||||
If you pass in a real request object as original_request, additional information (e.g. client IP, cookies)
|
||||
will be included in the dummy request.
|
||||
"""
|
||||
url = self.full_url
|
||||
if url:
|
||||
|
@ -1195,14 +1198,30 @@ class Page(six.with_metaclass(PageBase, MP_Node, index.Indexed, ClusterableModel
|
|||
path = '/'
|
||||
port = 80
|
||||
|
||||
request = WSGIRequest({
|
||||
dummy_values = {
|
||||
'REQUEST_METHOD': 'GET',
|
||||
'PATH_INFO': path,
|
||||
'SERVER_NAME': hostname,
|
||||
'SERVER_PORT': port,
|
||||
'HTTP_HOST': hostname,
|
||||
'wsgi.input': StringIO(),
|
||||
})
|
||||
}
|
||||
|
||||
# Add important values from the original request object, if it was provided.
|
||||
if original_request:
|
||||
if original_request.META.get('REMOTE_ADDR'):
|
||||
dummy_values['REMOTE_ADDR'] = original_request.META['REMOTE_ADDR']
|
||||
if original_request.META.get('HTTP_X_FORWARDED_FOR'):
|
||||
dummy_values['HTTP_X_FORWARDED_FOR'] = original_request.META['HTTP_X_FORWARDED_FOR']
|
||||
if original_request.META.get('HTTP_COOKIE'):
|
||||
dummy_values['HTTP_COOKIE'] = original_request.META['HTTP_COOKIE']
|
||||
if original_request.META.get('HTTP_USER_AGENT'):
|
||||
dummy_values['HTTP_USER_AGENT'] = original_request.META['HTTP_USER_AGENT']
|
||||
|
||||
# Add additional custom metadata sent by the caller.
|
||||
dummy_values.update(**meta)
|
||||
|
||||
request = WSGIRequest(dummy_values)
|
||||
|
||||
# Apply middleware to the request - see http://www.mellowmorning.com/2011/04/18/mock-django-request-for-testing/
|
||||
handler = BaseHandler()
|
||||
|
|
|
@ -10,6 +10,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.http import Http404, HttpRequest
|
||||
from django.test import Client, TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from wagtail.tests.testapp.models import (
|
||||
|
@ -1156,6 +1157,24 @@ class TestDummyRequest(TestCase):
|
|||
self.assertEqual(request.path, '/events/')
|
||||
self.assertEqual(request.META['HTTP_HOST'], 'localhost')
|
||||
|
||||
def test_dummy_request_for_accessible_page_with_original_request(self):
|
||||
event_index = Page.objects.get(url_path='/home/events/')
|
||||
original_headers = {
|
||||
'REMOTE_ADDR': '192.168.0.1',
|
||||
'HTTP_X_FORWARDED_FOR': '192.168.0.2,192.168.0.3',
|
||||
'HTTP_COOKIE': "test=1;blah=2",
|
||||
'HTTP_USER_AGENT': "Test Agent",
|
||||
}
|
||||
factory = RequestFactory(**original_headers)
|
||||
original_request = factory.get('/home/events/')
|
||||
request = event_index.dummy_request(original_request)
|
||||
|
||||
# request should have the all the special headers we set in original_request
|
||||
self.assertEqual(request.META['REMOTE_ADDR'], original_request.META['REMOTE_ADDR'])
|
||||
self.assertEqual(request.META['HTTP_X_FORWARDED_FOR'], original_request.META['HTTP_X_FORWARDED_FOR'])
|
||||
self.assertEqual(request.META['HTTP_COOKIE'], original_request.META['HTTP_COOKIE'])
|
||||
self.assertEqual(request.META['HTTP_USER_AGENT'], original_request.META['HTTP_USER_AGENT'])
|
||||
|
||||
@override_settings(ALLOWED_HOSTS=['production.example.com'])
|
||||
def test_dummy_request_for_inaccessible_page_should_use_valid_host(self):
|
||||
root_page = Page.objects.get(url_path='/')
|
||||
|
|
Ładowanie…
Reference in New Issue