from __future__ import unicode_literals
import inspect
from bs4 import BeautifulSoup
from django.conf import settings
from django.http import Http404, HttpResponse
from django.template import loader
from django.views.generic import View
from wagtail.wagtailcore import hooks
from wagtail.wagtailcore.views import serve as wagtail_serve
from wagtailsharing.models import SharingSite
class ServeView(View):
def get(self, request, path):
try:
sharing_site = SharingSite.find_for_request(request)
except SharingSite.DoesNotExist:
return wagtail_serve(request, path)
page, args, kwargs = self.get_requested_page(
sharing_site.site,
request,
path
)
return self.serve_latest_revision(page, request, args, kwargs)
@staticmethod
def get_requested_page(site, request, path):
"""Retrieve a page from a site given a request and path.
This method uses the standard `wagtail.wagtailcore.Page.route` method
to retrieve a page using its path from the given site root.
If a requested page exists and is published, the result of `Page.route`
can be returned directly.
If the page exists but is not yet published, `Page.route` raises an
`Http404`, which this method tries to catch and handle. `Page.route`
raises `Http404` in two cases: if no page with the given path exists
and if a page exists but is unpublished. This method catches both
cases, and, if they fall into the latter category, returns the
requested page back to the caller despite its draft status.
"""
path_components = [
component for component in path.split('/') if component
]
try:
return site.root_page.route(request, path_components)
except Http404:
exception_source = inspect.trace()[-1]
stack_frame = exception_source[0]
page = stack_frame.f_locals['self']
path_components = stack_frame.f_locals['path_components']
if path_components:
raise
return page, [], {}
@classmethod
def serve_latest_revision(cls, page, request, args, kwargs):
# Call the before_serve_page hook.
for fn in hooks.get_hooks('before_serve_page'):
result = fn(page, request, args, kwargs)
if isinstance(result, HttpResponse):
return result
# Get the latest revision for the requested page.
page = page.get_latest_revision_as_page()
# Generate the page response.
response = page.serve(request, *args, **kwargs)
# Do appropriate response postprocessing.
response = cls.postprocess_response(response)
return response
@classmethod
def postprocess_response(cls, response):
if getattr(settings, 'WAGTAILSHARING_BANNER', True):
cls.add_response_banner(response)
return response
@staticmethod
def add_response_banner(response):
response.render()
html = BeautifulSoup(response.content, 'html.parser')
banner_template_name = 'wagtailsharing/banner.html'
banner_template = loader.get_template(banner_template_name)
banner_html = banner_template.render()
banner = BeautifulSoup(banner_html, 'html.parser')
if html.body:
html.body.insert(0, banner)
response.content = html.prettify()
return response
|