From 18864102ee106ee930ed2dd15bee6bc62763afa3 Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Thu, 8 Jun 2017 00:13:07 +0100 Subject: [PATCH] Add hook and authenticate_with_password view for document view restrictions --- .../wagtailcore/password_required.html | 4 ++- .../wagtaildocs/password_required.html | 6 ++++ wagtail/wagtaildocs/urls.py | 2 ++ wagtail/wagtaildocs/views/serve.py | 33 ++++++++++++++++++- wagtail/wagtaildocs/wagtail_hooks.py | 33 +++++++++++++++++++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 wagtail/wagtaildocs/templates/wagtaildocs/password_required.html diff --git a/wagtail/wagtailcore/templates/wagtailcore/password_required.html b/wagtail/wagtailcore/templates/wagtailcore/password_required.html index 04d7cfaeb..a10d8ab59 100644 --- a/wagtail/wagtailcore/templates/wagtailcore/password_required.html +++ b/wagtail/wagtailcore/templates/wagtailcore/password_required.html @@ -6,7 +6,9 @@

{% trans "Password required" %}

-

{% trans "You need a password to access this page." %}

+ {% block password_required_message %} +

{% trans "You need a password to access this page." %}

+ {% endblock %}
{% csrf_token %} {{ form.as_p }} diff --git a/wagtail/wagtaildocs/templates/wagtaildocs/password_required.html b/wagtail/wagtaildocs/templates/wagtaildocs/password_required.html new file mode 100644 index 000000000..56c452c3b --- /dev/null +++ b/wagtail/wagtaildocs/templates/wagtaildocs/password_required.html @@ -0,0 +1,6 @@ +{% extends "wagtailcore/password_required.html" %} +{% load i18n %} + +{% block password_required_message %} +

{% trans "You need a password to access this document." %}

+{% endblock %} diff --git a/wagtail/wagtaildocs/urls.py b/wagtail/wagtaildocs/urls.py index 4d6314db2..cb3030163 100644 --- a/wagtail/wagtaildocs/urls.py +++ b/wagtail/wagtaildocs/urls.py @@ -6,4 +6,6 @@ from wagtail.wagtaildocs.views import serve urlpatterns = [ url(r'^(\d+)/(.*)$', serve.serve, name='wagtaildocs_serve'), + url(r'^authenticate_with_password/(\d+)/$', serve.authenticate_with_password, + name='wagtaildocs_authenticate_with_password'), ] diff --git a/wagtail/wagtaildocs/views/serve.py b/wagtail/wagtaildocs/views/serve.py index 9a6f19c1c..c5b92b2c5 100644 --- a/wagtail/wagtaildocs/views/serve.py +++ b/wagtail/wagtaildocs/views/serve.py @@ -3,13 +3,17 @@ from __future__ import absolute_import, unicode_literals from wsgiref.util import FileWrapper from django.conf import settings +from django.core.urlresolvers import reverse from django.http import BadHeaderError, Http404, HttpResponse, StreamingHttpResponse -from django.shortcuts import get_object_or_404 +from django.shortcuts import get_object_or_404, redirect +from django.template.response import TemplateResponse from unidecode import unidecode from wagtail.utils import sendfile_streaming_backend from wagtail.utils.sendfile import sendfile from wagtail.wagtailcore import hooks +from wagtail.wagtailcore.forms import PasswordViewRestrictionForm +from wagtail.wagtailcore.models import CollectionViewRestriction from wagtail.wagtaildocs.models import document_served, get_document_model @@ -74,3 +78,30 @@ def serve(request, document_id, document_filename): response['Content-Length'] = doc.file.size return response + + +def authenticate_with_password(request, restriction_id): + """ + Handle a submission of PasswordViewRestrictionForm to grant view access over a + subtree that is protected by a PageViewRestriction + """ + restriction = get_object_or_404(CollectionViewRestriction, id=restriction_id) + + if request.method == 'POST': + form = PasswordViewRestrictionForm(request.POST, instance=restriction) + if form.is_valid(): + restriction.mark_as_passed(request) + + return redirect(form.cleaned_data['return_url']) + else: + form = PasswordViewRestrictionForm(instance=restriction) + + action_url = reverse('wagtaildocs_authenticate_with_password', args=[restriction.id]) + + password_required_template = getattr(settings, 'DOCUMENT_PASSWORD_REQUIRED_TEMPLATE', 'wagtaildocs/password_required.html') + + context = { + 'form': form, + 'action_url': action_url + } + return TemplateResponse(request, password_required_template, context) diff --git a/wagtail/wagtaildocs/wagtail_hooks.py b/wagtail/wagtaildocs/wagtail_hooks.py index b54d24c64..71454ea37 100644 --- a/wagtail/wagtaildocs/wagtail_hooks.py +++ b/wagtail/wagtaildocs/wagtail_hooks.py @@ -1,8 +1,10 @@ from __future__ import absolute_import, unicode_literals +from django.conf import settings from django.conf.urls import include, url from django.contrib.staticfiles.templatetags.staticfiles import static from django.core import urlresolvers +from django.template.response import TemplateResponse from django.utils.html import format_html, format_html_join from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext @@ -11,6 +13,8 @@ from wagtail.wagtailadmin.menu import MenuItem from wagtail.wagtailadmin.search import SearchArea from wagtail.wagtailadmin.site_summary import SummaryItem from wagtail.wagtailcore import hooks +from wagtail.wagtailcore.models import BaseViewRestriction +from wagtail.wagtailcore.wagtail_hooks import require_wagtail_login from wagtail.wagtaildocs import admin_urls from wagtail.wagtaildocs.api.admin.endpoints import DocumentsAdminAPIEndpoint from wagtail.wagtaildocs.forms import GroupDocumentPermissionFormSet @@ -130,3 +134,32 @@ def describe_collection_docs(collection): ) % {'count': docs_count}, 'url': url, } + + +@hooks.register('before_serve_document') +def check_view_restrictions(document, request): + """ + Check whether there are any view restrictions on this document which are + not fulfilled by the given request object. If there are, return an + HttpResponse that will notify the user of that restriction (and possibly + include a password / login form that will allow them to proceed). If + there are no such restrictions, return None + """ + for restriction in document.collection.get_view_restrictions(): + if not restriction.accept_request(request): + if restriction.restriction_type == BaseViewRestriction.PASSWORD: + from wagtail.wagtailcore.forms import PasswordViewRestrictionForm + form = PasswordViewRestrictionForm(instance=restriction, + initial={'return_url': request.get_full_path()}) + action_url = urlresolvers.reverse('wagtaildocs_authenticate_with_password', args=[restriction.id]) + + password_required_template = getattr(settings, 'DOCUMENT_PASSWORD_REQUIRED_TEMPLATE', 'wagtaildocs/password_required.html') + + context = { + 'form': form, + 'action_url': action_url + } + return TemplateResponse(request, password_required_template, context) + + elif restriction.restriction_type in [BaseViewRestriction.LOGIN, BaseViewRestriction.GROUPS]: + return require_wagtail_login(next=request.get_full_path())