From e4008a814824a24f36c288f7309c4867b8919870 Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Wed, 4 Jun 2014 15:28:03 +0100 Subject: [PATCH] implement form submission logic for the password form --- wagtail/wagtailcore/forms.py | 16 +++++++++++++ wagtail/wagtailcore/models.py | 18 +++++++++----- .../wagtailcore/password_required.html | 6 +++++ wagtail/wagtailcore/urls.py | 5 +++- wagtail/wagtailcore/views.py | 24 +++++++++++++++++++ wagtail/wagtailcore/wagtail_hooks.py | 10 +++++++- 6 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 wagtail/wagtailcore/forms.py diff --git a/wagtail/wagtailcore/forms.py b/wagtail/wagtailcore/forms.py new file mode 100644 index 000000000..1b83c8c94 --- /dev/null +++ b/wagtail/wagtailcore/forms.py @@ -0,0 +1,16 @@ +from django import forms + +class PasswordPageViewRestrictionForm(forms.Form): + password = forms.CharField(label="Password", widget=forms.PasswordInput) + return_url = forms.CharField(widget=forms.HiddenInput) + + def __init__(self, *args, **kwargs): + self.restriction = kwargs.pop('instance') + super(PasswordPageViewRestrictionForm, self).__init__(*args, **kwargs) + + def clean_password(self): + data = self.cleaned_data['password'] + if data != self.restriction.password: + raise forms.ValidationError("The password you have entered is not correct. Please try again.") + + return data diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 59c9eb861..08e1b612b 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -812,12 +812,18 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, Indexed)): return self.get_siblings(inclusive).filter(path__lte=self.path).order_by('-path') password_required_template = getattr(settings, 'PASSWORD_REQUIRED_TEMPLATE', 'wagtailcore/password_required.html') - def serve_password_required_response(self, request, form): - return TemplateResponse(request, self.password_required_template, { - 'self': self, - 'request': request, - 'form': form, - }) + def serve_password_required_response(self, request, form, action_url): + """ + Serve a response indicating that the user has been denied access to view this page, + and must supply a password. + form = a Django form object containing the password input + (and zero or more hidden fields that also need to be output on the template) + action_url = URL that this form should be POSTed to + """ + context = self.get_context(request) + context['form'] = form + context['action_url'] = action_url + return TemplateResponse(request, self.password_required_template, context) def get_navigation_menu_items(): diff --git a/wagtail/wagtailcore/templates/wagtailcore/password_required.html b/wagtail/wagtailcore/templates/wagtailcore/password_required.html index d4ee0b1fc..d7601ca69 100644 --- a/wagtail/wagtailcore/templates/wagtailcore/password_required.html +++ b/wagtail/wagtailcore/templates/wagtailcore/password_required.html @@ -5,5 +5,11 @@

Password required

+

You need a password to access this page.

+
+ {% csrf_token %} + {{ form.as_p }} + +
diff --git a/wagtail/wagtailcore/urls.py b/wagtail/wagtailcore/urls.py index f0336fec4..9777dea8a 100644 --- a/wagtail/wagtailcore/urls.py +++ b/wagtail/wagtailcore/urls.py @@ -2,7 +2,10 @@ from django.conf.urls import url from wagtail.wagtailcore import views urlpatterns = [ - # All front-end views are handled through Wagtail's core.views.serve mechanism. + url(r'^_util/authenticate_with_password/(\d+)/(\d+)/$', views.authenticate_with_password, + name='wagtailcore_authenticate_with_password'), + + # Front-end page views are handled through Wagtail's core.views.serve mechanism. # Here we match a (possibly empty) list of path segments, each followed by # a '/'. If a trailing slash is not present, we leave CommonMiddleware to # handle it as usual (i.e. redirect it to the trailing slash version if diff --git a/wagtail/wagtailcore/views.py b/wagtail/wagtailcore/views.py index 0872dd68f..bd12d7f97 100644 --- a/wagtail/wagtailcore/views.py +++ b/wagtail/wagtailcore/views.py @@ -1,8 +1,12 @@ import warnings from django.http import HttpResponse, Http404 +from django.shortcuts import get_object_or_404, redirect +from django.core.urlresolvers import reverse from wagtail.wagtailcore import hooks +from wagtail.wagtailcore.models import Page, PageViewRestriction +from wagtail.wagtailcore.forms import PasswordPageViewRestrictionForm def serve(request, path): @@ -26,3 +30,23 @@ def serve(request, path): return result return page.serve(request) + + +def authenticate_with_password(request, page_view_restriction_id, page_id): + """ + Handle a submission of PasswordPageViewRestrictionForm to grant view access over a + subtree that is protected by a PageViewRestriction + """ + restriction = get_object_or_404(PageViewRestriction, id=page_view_restriction_id) + page = get_object_or_404(Page, id=page_id).specific + + if request.POST: + form = PasswordPageViewRestrictionForm(request.POST, instance=restriction) + if form.is_valid(): + # TODO: record 'has authenticated against this page view restriction' flag in the session + return redirect(form.cleaned_data['return_url']) + else: + form = PasswordPageViewRestrictionForm(instance=restriction) + + action_url = reverse('wagtailcore_authenticate_with_password', args=[restriction.id, page.id]) + return page.serve_password_required_response(request, form, action_url) diff --git a/wagtail/wagtailcore/wagtail_hooks.py b/wagtail/wagtailcore/wagtail_hooks.py index 347194c32..ccac0bd43 100644 --- a/wagtail/wagtailcore/wagtail_hooks.py +++ b/wagtail/wagtailcore/wagtail_hooks.py @@ -1,8 +1,16 @@ +from django.core.urlresolvers import reverse + from wagtail.wagtailcore import hooks from wagtail.wagtailcore.models import PageViewRestriction +from wagtail.wagtailcore.forms import PasswordPageViewRestrictionForm def check_view_restrictions(page, request): restrictions = PageViewRestriction.objects.filter(page__in=page.get_ancestors(inclusive=True)) + for restriction in restrictions: - return page.serve_password_required_response(request, None) + form = PasswordPageViewRestrictionForm(instance=restriction, + initial={'return_url': request.get_full_path()}) + action_url = reverse('wagtailcore_authenticate_with_password', args=[restriction.id, page.id]) + return page.serve_password_required_response(request, form, action_url) + hooks.register('before_serve_page', check_view_restrictions)