123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- from warnings import warn
- from django.conf import settings
- from django.http import FileResponse, Http404, HttpResponse
- from django.shortcuts import get_object_or_404, redirect
- from django.template.response import TemplateResponse
- from django.urls import reverse
- from django.utils.http import url_has_allowed_host_and_scheme
- from django.views.decorators.http import etag
- from wagtail import hooks
- from wagtail.documents import get_document_model
- from wagtail.documents.models import document_served
- from wagtail.forms import PasswordViewRestrictionForm
- from wagtail.models import CollectionViewRestriction
- from wagtail.utils import sendfile_streaming_backend
- from wagtail.utils.deprecation import RemovedInWagtail70Warning
- from wagtail.utils.sendfile import sendfile
- def document_etag(request, document_id, document_filename):
- Document = get_document_model()
- if hasattr(Document, "file_hash"):
- return (
- Document.objects.filter(id=document_id)
- .values_list("file_hash", flat=True)
- .first()
- )
- @etag(document_etag)
- def serve(request, document_id, document_filename):
- Document = get_document_model()
- doc = get_object_or_404(Document, id=document_id)
-
-
-
- if doc.filename != document_filename:
- raise Http404("This document does not match the given filename.")
- for fn in hooks.get_hooks("before_serve_document"):
- result = fn(doc, request)
- if isinstance(result, HttpResponse):
- return result
-
- document_served.send(sender=Document, instance=doc, request=request)
- try:
- local_path = doc.file.path
- except NotImplementedError:
- local_path = None
- try:
- direct_url = doc.file.url
- except NotImplementedError:
- direct_url = None
- serve_method = getattr(settings, "WAGTAILDOCS_SERVE_METHOD", None)
-
-
-
- if serve_method is None:
- if direct_url and not local_path:
- serve_method = "redirect"
- else:
- serve_method = "serve_view"
- if serve_method in ("redirect", "direct") and direct_url:
-
-
-
-
-
-
- return redirect(direct_url)
- if local_path:
-
-
- sendfile_opts = {
- "attachment": (doc.content_disposition != "inline"),
- "attachment_filename": doc.filename,
- "mimetype": doc.content_type,
- }
- if not hasattr(settings, "SENDFILE_BACKEND"):
-
- sendfile_opts["backend"] = sendfile_streaming_backend.sendfile
- response = sendfile(request, local_path, **sendfile_opts)
- else:
-
-
-
-
-
- response = FileResponse(doc.file, doc.content_type)
-
-
- response["Content-Disposition"] = doc.content_disposition
-
- response["Content-Length"] = doc.file.size
-
- if getattr(settings, "WAGTAILDOCS_BLOCK_EMBEDDED_CONTENT", True):
- response["Content-Security-Policy"] = "default-src 'none'"
-
- response["X-Content-Type-Options"] = "nosniff"
- 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():
- return_url = form.cleaned_data["return_url"]
- if not url_has_allowed_host_and_scheme(
- return_url, request.get_host(), request.is_secure()
- ):
- return_url = settings.LOGIN_REDIRECT_URL
- restriction.mark_as_passed(request)
- return redirect(return_url)
- else:
- form = PasswordViewRestrictionForm(instance=restriction)
- action_url = reverse(
- "wagtaildocs_authenticate_with_password", args=[restriction.id]
- )
- password_required_template = getattr(
- settings,
- "WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE",
- "wagtaildocs/password_required.html",
- )
- if hasattr(settings, "DOCUMENT_PASSWORD_REQUIRED_TEMPLATE"):
- warn(
- "The `DOCUMENT_PASSWORD_REQUIRED_TEMPLATE` setting is deprecated - use `WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE` instead.",
- category=RemovedInWagtail70Warning,
- )
- password_required_template = getattr(
- settings,
- "DOCUMENT_PASSWORD_REQUIRED_TEMPLATE",
- password_required_template,
- )
- context = {"form": form, "action_url": action_url}
- return TemplateResponse(request, password_required_template, context)
|