Initial commit
This commit is contained in:
0
env/lib/python3.10/site-packages/wagtail/documents/views/__init__.py
vendored
Normal file
0
env/lib/python3.10/site-packages/wagtail/documents/views/__init__.py
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/__init__.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/__init__.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/chooser.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/chooser.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/documents.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/documents.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/multiple.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/multiple.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/serve.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/views/__pycache__/serve.cpython-310.pyc
vendored
Normal file
Binary file not shown.
5
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/__init__.py
vendored
Normal file
5
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/__init__.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
from .add_tags import AddTagsBulkAction
|
||||
from .add_to_collection import AddToCollectionBulkAction
|
||||
from .delete import DeleteBulkAction
|
||||
|
||||
__all__ = ["AddToCollectionBulkAction", "AddTagsBulkAction", "DeleteBulkAction"]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
44
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/add_tags.py
vendored
Normal file
44
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/add_tags.py
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import ngettext
|
||||
|
||||
from wagtail.admin import widgets
|
||||
from wagtail.documents.views.bulk_actions.document_bulk_action import DocumentBulkAction
|
||||
|
||||
|
||||
class TagForm(forms.Form):
|
||||
tags = forms.Field(label=_("Tags"), widget=widgets.AdminTagWidget)
|
||||
|
||||
|
||||
class AddTagsBulkAction(DocumentBulkAction):
|
||||
display_name = _("Tag")
|
||||
action_type = "add_tags"
|
||||
aria_label = _("Add tags to the selected documents")
|
||||
template_name = "wagtaildocs/bulk_actions/confirm_bulk_add_tags.html"
|
||||
action_priority = 20
|
||||
form_class = TagForm
|
||||
|
||||
def check_perm(self, document):
|
||||
return self.permission_policy.user_has_permission_for_instance(
|
||||
self.request.user, "change", document
|
||||
)
|
||||
|
||||
def get_execution_context(self):
|
||||
return {"tags": self.cleaned_form.cleaned_data["tags"].split(",")}
|
||||
|
||||
@classmethod
|
||||
def execute_action(cls, objects, tags=[], **kwargs):
|
||||
num_parent_objects = 0
|
||||
if not tags:
|
||||
return
|
||||
for document in objects:
|
||||
num_parent_objects += 1
|
||||
document.tags.add(*tags)
|
||||
return num_parent_objects, 0
|
||||
|
||||
def get_success_message(self, num_parent_objects, num_child_objects):
|
||||
return ngettext(
|
||||
"New tags have been added to %(num_parent_objects)d document",
|
||||
"New tags have been added to %(num_parent_objects)d documents",
|
||||
num_parent_objects,
|
||||
) % {"num_parent_objects": num_parent_objects}
|
||||
57
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/add_to_collection.py
vendored
Normal file
57
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/add_to_collection.py
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import ngettext
|
||||
|
||||
from wagtail.documents.views.bulk_actions.document_bulk_action import DocumentBulkAction
|
||||
|
||||
|
||||
class CollectionForm(forms.Form):
|
||||
def __init__(self, *args, **kwargs):
|
||||
user = kwargs.pop("user", None)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["collection"] = forms.ModelChoiceField(
|
||||
label=_("Collection"),
|
||||
queryset=DocumentBulkAction.permission_policy.collections_user_has_permission_for(
|
||||
user, "add"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class AddToCollectionBulkAction(DocumentBulkAction):
|
||||
display_name = _("Add to collection")
|
||||
action_type = "add_to_collection"
|
||||
aria_label = _("Add selected documents to collection")
|
||||
template_name = "wagtaildocs/bulk_actions/confirm_bulk_add_to_collection.html"
|
||||
action_priority = 30
|
||||
form_class = CollectionForm
|
||||
collection = None
|
||||
|
||||
def check_perm(self, document):
|
||||
return self.permission_policy.user_has_permission_for_instance(
|
||||
self.request.user, "change", document
|
||||
)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
return {**super().get_form_kwargs(), "user": self.request.user}
|
||||
|
||||
def get_execution_context(self):
|
||||
return {"collection": self.cleaned_form.cleaned_data["collection"]}
|
||||
|
||||
@classmethod
|
||||
def execute_action(cls, objects, collection=None, **kwargs):
|
||||
if collection is None:
|
||||
return
|
||||
num_parent_objects = (
|
||||
cls.get_default_model()
|
||||
.objects.filter(pk__in=[obj.pk for obj in objects])
|
||||
.update(collection=collection)
|
||||
)
|
||||
return num_parent_objects, 0
|
||||
|
||||
def get_success_message(self, num_parent_objects, num_child_objects):
|
||||
collection = self.cleaned_form.cleaned_data["collection"]
|
||||
return ngettext(
|
||||
"%(num_parent_objects)d document has been added to %(collection)s",
|
||||
"%(num_parent_objects)d documents have been added to %(collection)s",
|
||||
num_parent_objects,
|
||||
) % {"num_parent_objects": num_parent_objects, "collection": collection}
|
||||
33
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/delete.py
vendored
Normal file
33
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/delete.py
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import ngettext
|
||||
|
||||
from wagtail.documents.views.bulk_actions.document_bulk_action import DocumentBulkAction
|
||||
|
||||
|
||||
class DeleteBulkAction(DocumentBulkAction):
|
||||
display_name = _("Delete")
|
||||
action_type = "delete"
|
||||
aria_label = _("Delete selected documents")
|
||||
template_name = "wagtaildocs/bulk_actions/confirm_bulk_delete.html"
|
||||
action_priority = 100
|
||||
classes = {"serious"}
|
||||
|
||||
def check_perm(self, document):
|
||||
return self.permission_policy.user_has_permission_for_instance(
|
||||
self.request.user, "delete", document
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute_action(cls, objects, **kwargs):
|
||||
num_parent_objects = len(objects)
|
||||
cls.get_default_model().objects.filter(
|
||||
pk__in=[obj.pk for obj in objects]
|
||||
).delete()
|
||||
return num_parent_objects, 0
|
||||
|
||||
def get_success_message(self, num_parent_objects, num_child_objects):
|
||||
return ngettext(
|
||||
"%(num_parent_objects)d document has been deleted",
|
||||
"%(num_parent_objects)d documents have been deleted",
|
||||
num_parent_objects,
|
||||
) % {"num_parent_objects": num_parent_objects}
|
||||
36
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/document_bulk_action.py
vendored
Normal file
36
env/lib/python3.10/site-packages/wagtail/documents/views/bulk_actions/document_bulk_action.py
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
from wagtail.admin.views.bulk_action import BulkAction
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.documents.permissions import (
|
||||
permission_policy as documents_permission_policy,
|
||||
)
|
||||
|
||||
|
||||
class DocumentBulkAction(BulkAction):
|
||||
permission_policy = documents_permission_policy
|
||||
models = [get_document_model()]
|
||||
|
||||
def get_all_objects_in_listing_query(self, parent_id):
|
||||
listing_objects = self.model.objects.all()
|
||||
if parent_id is not None:
|
||||
listing_objects = listing_objects.filter(collection_id=parent_id)
|
||||
|
||||
listing_objects = listing_objects.values_list("pk", flat=True)
|
||||
|
||||
if "q" in self.request.GET:
|
||||
query_string = self.request.GET.get("q", "")
|
||||
listing_objects = listing_objects.search(query_string).results()
|
||||
|
||||
return listing_objects
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["items_with_no_access"] = [
|
||||
{
|
||||
"item": document,
|
||||
"can_edit": self.permission_policy.user_has_permission_for_instance(
|
||||
self.request.user, "change", document
|
||||
),
|
||||
}
|
||||
for document in context["items_with_no_access"]
|
||||
]
|
||||
return context
|
||||
195
env/lib/python3.10/site-packages/wagtail/documents/views/chooser.py
vendored
Normal file
195
env/lib/python3.10/site-packages/wagtail/documents/views/chooser.py
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
from django import forms
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic.base import View
|
||||
|
||||
from wagtail.admin.staticfiles import versioned_static
|
||||
from wagtail.admin.ui.tables import Column, DateColumn, DownloadColumn
|
||||
from wagtail.admin.views.generic.chooser import (
|
||||
BaseChooseView,
|
||||
ChooseResultsViewMixin,
|
||||
ChooseViewMixin,
|
||||
ChosenResponseMixin,
|
||||
ChosenViewMixin,
|
||||
CreateViewMixin,
|
||||
CreationFormMixin,
|
||||
)
|
||||
from wagtail.admin.viewsets.chooser import ChooserViewSet
|
||||
from wagtail.admin.widgets import BaseChooser, BaseChooserAdapter
|
||||
from wagtail.blocks import ChooserBlock
|
||||
from wagtail.documents import get_document_model, get_document_model_string
|
||||
from wagtail.documents.permissions import permission_policy
|
||||
|
||||
|
||||
class DocumentChosenResponseMixin(ChosenResponseMixin):
|
||||
def get_chosen_response_data(self, document):
|
||||
response_data = super().get_chosen_response_data(document)
|
||||
response_data.update(
|
||||
{
|
||||
"url": document.url,
|
||||
"filename": document.filename,
|
||||
}
|
||||
)
|
||||
return response_data
|
||||
|
||||
|
||||
class DocumentCreationFormMixin(CreationFormMixin):
|
||||
creation_tab_id = "upload"
|
||||
|
||||
def get_creation_form_class(self):
|
||||
from wagtail.documents.forms import get_document_form
|
||||
|
||||
return get_document_form(self.model)
|
||||
|
||||
def get_creation_form_kwargs(self):
|
||||
kwargs = super().get_creation_form_kwargs()
|
||||
kwargs.update(
|
||||
{
|
||||
"user": self.request.user,
|
||||
"prefix": "document-chooser-upload",
|
||||
}
|
||||
)
|
||||
if self.request.method in ("POST", "PUT"):
|
||||
kwargs["instance"] = self.model(uploaded_by_user=self.request.user)
|
||||
|
||||
return kwargs
|
||||
|
||||
|
||||
class BaseDocumentChooseView(BaseChooseView):
|
||||
results_template_name = "wagtaildocs/chooser/results.html"
|
||||
per_page = 10
|
||||
ordering = "-created_at"
|
||||
construct_queryset_hook_name = "construct_document_chooser_queryset"
|
||||
|
||||
def get_object_list(self):
|
||||
return self.permission_policy.instances_user_has_any_permission_for(
|
||||
self.request.user, ["choose"]
|
||||
)
|
||||
|
||||
def get_filter_form(self):
|
||||
FilterForm = self.get_filter_form_class()
|
||||
return FilterForm(self.request.GET, collections=self.collections)
|
||||
|
||||
@cached_property
|
||||
def collections(self):
|
||||
collections = self.permission_policy.collections_user_has_permission_for(
|
||||
self.request.user, "choose"
|
||||
)
|
||||
if len(collections) < 2:
|
||||
return None
|
||||
|
||||
return collections
|
||||
|
||||
@property
|
||||
def columns(self):
|
||||
columns = super().columns + [
|
||||
DownloadColumn("filename", label=_("File")),
|
||||
DateColumn("created_at", label=_("Created"), width="16%"),
|
||||
]
|
||||
|
||||
if self.collections:
|
||||
columns.insert(2, Column("collection", label=_("Collection")))
|
||||
|
||||
return columns
|
||||
|
||||
def get(self, request):
|
||||
self.model = get_document_model()
|
||||
return super().get(request)
|
||||
|
||||
|
||||
class DocumentChooseViewMixin(ChooseViewMixin):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["collections"] = self.collections
|
||||
return context
|
||||
|
||||
|
||||
class DocumentChooseView(
|
||||
DocumentChooseViewMixin, DocumentCreationFormMixin, BaseDocumentChooseView
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
class DocumentChooseResultsView(
|
||||
ChooseResultsViewMixin, DocumentCreationFormMixin, BaseDocumentChooseView
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
class DocumentChosenView(ChosenViewMixin, DocumentChosenResponseMixin, View):
|
||||
def get(self, request, *args, pk, **kwargs):
|
||||
self.model = get_document_model()
|
||||
return super().get(request, *args, pk, **kwargs)
|
||||
|
||||
|
||||
class DocumentChooserUploadView(
|
||||
CreateViewMixin, DocumentCreationFormMixin, DocumentChosenResponseMixin, View
|
||||
):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.model = get_document_model()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class BaseAdminDocumentChooser(BaseChooser):
|
||||
classname = "document-chooser"
|
||||
js_constructor = "DocumentChooser"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.model = get_document_model_string()
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
return forms.Media(
|
||||
js=[
|
||||
versioned_static("wagtaildocs/js/document-chooser-modal.js"),
|
||||
versioned_static("wagtaildocs/js/document-chooser.js"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class DocumentChooserAdapter(BaseChooserAdapter):
|
||||
js_constructor = "wagtail.documents.widgets.DocumentChooser"
|
||||
|
||||
@cached_property
|
||||
def media(self):
|
||||
return forms.Media(
|
||||
js=[
|
||||
versioned_static("wagtaildocs/js/document-chooser-modal.js"),
|
||||
versioned_static("wagtaildocs/js/document-chooser-telepath.js"),
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class BaseDocumentChooserBlock(ChooserBlock):
|
||||
def render_basic(self, value, context=None):
|
||||
if value:
|
||||
return format_html('<a href="{0}">{1}</a>', value.url, value.title)
|
||||
else:
|
||||
return ""
|
||||
|
||||
|
||||
class DocumentChooserViewSet(ChooserViewSet):
|
||||
choose_view_class = DocumentChooseView
|
||||
choose_results_view_class = DocumentChooseResultsView
|
||||
chosen_view_class = DocumentChosenView
|
||||
create_view_class = DocumentChooserUploadView
|
||||
base_widget_class = BaseAdminDocumentChooser
|
||||
widget_telepath_adapter_class = DocumentChooserAdapter
|
||||
base_block_class = BaseDocumentChooserBlock
|
||||
permission_policy = permission_policy
|
||||
|
||||
icon = "doc-full-inverse"
|
||||
choose_one_text = _("Choose a document")
|
||||
create_action_label = _("Upload")
|
||||
create_action_clicked_label = _("Uploading…")
|
||||
choose_another_text = _("Choose another document")
|
||||
edit_item_text = _("Edit this document")
|
||||
|
||||
|
||||
viewset = DocumentChooserViewSet(
|
||||
"wagtaildocs_chooser",
|
||||
model=get_document_model_string(),
|
||||
url_prefix="documents/chooser",
|
||||
)
|
||||
318
env/lib/python3.10/site-packages/wagtail/documents/views/documents.py
vendored
Normal file
318
env/lib/python3.10/site-packages/wagtail/documents/views/documents.py
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
import os
|
||||
|
||||
from django.contrib.admin.utils import quote
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy, ngettext
|
||||
|
||||
from wagtail.admin import messages
|
||||
from wagtail.admin.auth import PermissionPolicyChecker
|
||||
from wagtail.admin.filters import BaseMediaFilterSet
|
||||
from wagtail.admin.ui.tables import (
|
||||
BulkActionsCheckboxColumn,
|
||||
Column,
|
||||
DateColumn,
|
||||
DownloadColumn,
|
||||
Table,
|
||||
TitleColumn,
|
||||
)
|
||||
from wagtail.admin.utils import get_valid_next_url_from_request, set_query_params
|
||||
from wagtail.admin.views import generic
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.documents.forms import get_document_form
|
||||
from wagtail.documents.permissions import permission_policy
|
||||
|
||||
permission_checker = PermissionPolicyChecker(permission_policy)
|
||||
Document = get_document_model()
|
||||
|
||||
|
||||
class BulkActionsColumn(BulkActionsCheckboxColumn):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, obj_type="document", **kwargs)
|
||||
|
||||
def get_header_context_data(self, parent_context):
|
||||
context = super().get_header_context_data(parent_context)
|
||||
parent = parent_context.get("current_collection")
|
||||
if parent:
|
||||
context["parent"] = parent.id
|
||||
return context
|
||||
|
||||
|
||||
class DocumentTable(Table):
|
||||
def get_context_data(self, parent_context):
|
||||
context = super().get_context_data(parent_context)
|
||||
context["current_collection"] = parent_context.get("current_collection")
|
||||
return context
|
||||
|
||||
|
||||
class DocumentsFilterSet(BaseMediaFilterSet):
|
||||
permission_policy = permission_policy
|
||||
|
||||
class Meta:
|
||||
model = Document
|
||||
fields = []
|
||||
|
||||
|
||||
class IndexView(generic.IndexView):
|
||||
permission_policy = permission_policy
|
||||
any_permission_required = ["add", "change", "delete"]
|
||||
context_object_name = "documents"
|
||||
page_title = gettext_lazy("Documents")
|
||||
header_icon = "doc-full-inverse"
|
||||
page_kwarg = "p"
|
||||
paginate_by = 20
|
||||
index_url_name = "wagtaildocs:index"
|
||||
index_results_url_name = "wagtaildocs:index_results"
|
||||
add_url_name = "wagtaildocs:add_multiple"
|
||||
edit_url_name = "wagtaildocs:edit"
|
||||
template_name = "wagtaildocs/documents/index.html"
|
||||
results_template_name = "wagtaildocs/documents/index_results.html"
|
||||
default_ordering = "title"
|
||||
table_class = DocumentTable
|
||||
filterset_class = DocumentsFilterSet
|
||||
model = get_document_model()
|
||||
add_item_label = gettext_lazy("Add a document")
|
||||
show_other_searches = True
|
||||
_show_breadcrumbs = True
|
||||
|
||||
def get_base_queryset(self):
|
||||
# Get documents (filtered by user permission)
|
||||
return self.permission_policy.instances_user_has_any_permission_for(
|
||||
self.request.user, ["change", "delete"]
|
||||
).select_related("collection")
|
||||
|
||||
@cached_property
|
||||
def current_collection(self):
|
||||
# Upon validation, the cleaned data is a Collection instance
|
||||
return self.filters and self.filters.form.cleaned_data.get("collection_id")
|
||||
|
||||
@cached_property
|
||||
def columns(self):
|
||||
columns = [
|
||||
BulkActionsColumn("bulk_actions"),
|
||||
TitleColumn(
|
||||
"title",
|
||||
label=_("Title"),
|
||||
sort_key="title",
|
||||
get_url=self.get_edit_url,
|
||||
get_title_id=lambda doc: f"document_{quote(doc.pk)}_title",
|
||||
),
|
||||
DownloadColumn("filename", label=_("File")),
|
||||
DateColumn(
|
||||
"created_at",
|
||||
label=_("Created"),
|
||||
sort_key="created_at",
|
||||
width="16%",
|
||||
),
|
||||
]
|
||||
if self.filters and "collection_id" in self.filters.filters:
|
||||
columns.insert(
|
||||
3,
|
||||
Column("collection", label=_("Collection"), accessor="collection.name"),
|
||||
)
|
||||
return columns
|
||||
|
||||
@cached_property
|
||||
def collections(self):
|
||||
collections = permission_policy.collections_user_has_any_permission_for(
|
||||
self.request.user, ["add", "change"]
|
||||
)
|
||||
if len(collections) < 2:
|
||||
collections = None
|
||||
return collections
|
||||
|
||||
def get_next_url(self):
|
||||
next_url = self.index_url
|
||||
request_query_string = self.request.META.get("QUERY_STRING")
|
||||
if request_query_string:
|
||||
next_url += "?" + request_query_string
|
||||
return next_url
|
||||
|
||||
def get_add_url(self):
|
||||
# Pass the collection filter to prefill the add form's collection field
|
||||
return set_query_params(
|
||||
super().get_add_url(),
|
||||
{"collection_id": self.current_collection and self.current_collection.pk},
|
||||
)
|
||||
|
||||
def get_edit_url(self, instance):
|
||||
return set_query_params(
|
||||
super().get_edit_url(instance),
|
||||
{"next": self.get_next_url()},
|
||||
)
|
||||
|
||||
def get_filterset_kwargs(self):
|
||||
kwargs = super().get_filterset_kwargs()
|
||||
kwargs["is_searching"] = self.is_searching
|
||||
return kwargs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["current_collection"] = self.current_collection
|
||||
return context
|
||||
|
||||
|
||||
@permission_checker.require("add")
|
||||
def add(request):
|
||||
Document = get_document_model()
|
||||
DocumentForm = get_document_form(Document)
|
||||
|
||||
if request.method == "POST":
|
||||
doc = Document(uploaded_by_user=request.user)
|
||||
form = DocumentForm(
|
||||
request.POST, request.FILES, instance=doc, user=request.user
|
||||
)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
|
||||
messages.success(
|
||||
request,
|
||||
_("Document '%(document_title)s' added.")
|
||||
% {"document_title": doc.title},
|
||||
buttons=[
|
||||
messages.button(
|
||||
reverse("wagtaildocs:edit", args=(doc.id,)), _("Edit")
|
||||
)
|
||||
],
|
||||
)
|
||||
return redirect("wagtaildocs:index")
|
||||
else:
|
||||
messages.error(request, _("The document could not be saved due to errors."))
|
||||
else:
|
||||
form = DocumentForm(user=request.user)
|
||||
|
||||
return TemplateResponse(
|
||||
request,
|
||||
"wagtaildocs/documents/add.html",
|
||||
{
|
||||
"form": form,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@permission_checker.require("change")
|
||||
def edit(request, document_id):
|
||||
Document = get_document_model()
|
||||
DocumentForm = get_document_form(Document)
|
||||
|
||||
doc = get_object_or_404(Document, id=document_id)
|
||||
|
||||
if not permission_policy.user_has_permission_for_instance(
|
||||
request.user, "change", doc
|
||||
):
|
||||
raise PermissionDenied
|
||||
|
||||
next_url = get_valid_next_url_from_request(request)
|
||||
|
||||
if request.method == "POST":
|
||||
form = DocumentForm(
|
||||
request.POST, request.FILES, instance=doc, user=request.user
|
||||
)
|
||||
if form.is_valid():
|
||||
doc = form.save()
|
||||
|
||||
edit_url = reverse("wagtaildocs:edit", args=(doc.id,))
|
||||
redirect_url = "wagtaildocs:index"
|
||||
if next_url:
|
||||
edit_url = f"{edit_url}?{urlencode({'next': next_url})}"
|
||||
redirect_url = next_url
|
||||
|
||||
messages.success(
|
||||
request,
|
||||
_("Document '%(document_title)s' updated")
|
||||
% {"document_title": doc.title},
|
||||
buttons=[messages.button(edit_url, _("Edit"))],
|
||||
)
|
||||
return redirect(redirect_url)
|
||||
else:
|
||||
messages.error(request, _("The document could not be saved due to errors."))
|
||||
else:
|
||||
form = DocumentForm(instance=doc, user=request.user)
|
||||
|
||||
try:
|
||||
local_path = doc.file.path
|
||||
except NotImplementedError:
|
||||
# Document is hosted externally (eg, S3)
|
||||
local_path = None
|
||||
|
||||
if local_path:
|
||||
# Give error if document file doesn't exist
|
||||
if not os.path.isfile(local_path):
|
||||
messages.error(
|
||||
request,
|
||||
_(
|
||||
"The file could not be found. Please change the source or delete the document"
|
||||
),
|
||||
buttons=[
|
||||
messages.button(
|
||||
reverse("wagtaildocs:delete", args=(doc.id,)), _("Delete")
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
return TemplateResponse(
|
||||
request,
|
||||
"wagtaildocs/documents/edit.html",
|
||||
{
|
||||
"document": doc,
|
||||
"filesize": doc.get_file_size(),
|
||||
"form": form,
|
||||
"user_can_delete": permission_policy.user_has_permission_for_instance(
|
||||
request.user, "delete", doc
|
||||
),
|
||||
"next": next_url,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class DeleteView(generic.DeleteView):
|
||||
model = get_document_model()
|
||||
pk_url_kwarg = "document_id"
|
||||
permission_policy = permission_policy
|
||||
permission_required = "delete"
|
||||
header_icon = "doc-full-inverse"
|
||||
usage_url_name = "wagtaildocs:document_usage"
|
||||
delete_url_name = "wagtaildocs:delete"
|
||||
index_url_name = "wagtaildocs:index"
|
||||
page_title = gettext_lazy("Delete document")
|
||||
|
||||
def user_has_permission(self, permission):
|
||||
return self.permission_policy.user_has_permission_for_instance(
|
||||
self.request.user, permission, self.object
|
||||
)
|
||||
|
||||
@property
|
||||
def confirmation_message(self):
|
||||
# This message will only appear in the singular, but we specify a plural
|
||||
# so it can share the translation string with confirm_bulk_delete.html
|
||||
return ngettext(
|
||||
"Are you sure you want to delete this document?",
|
||||
"Are you sure you want to delete these documents?",
|
||||
1,
|
||||
)
|
||||
|
||||
def get_success_message(self):
|
||||
return _("Document '%(document_title)s' deleted.") % {
|
||||
"document_title": self.object.title
|
||||
}
|
||||
|
||||
|
||||
class UsageView(generic.UsageView):
|
||||
model = get_document_model()
|
||||
pk_url_kwarg = "document_id"
|
||||
permission_policy = permission_policy
|
||||
permission_required = "change"
|
||||
header_icon = "doc-full-inverse"
|
||||
|
||||
def user_has_permission(self, permission):
|
||||
return self.permission_policy.user_has_permission_for_instance(
|
||||
self.request.user, permission, self.object
|
||||
)
|
||||
|
||||
def get_page_subtitle(self):
|
||||
return self.object.title
|
||||
121
env/lib/python3.10/site-packages/wagtail/documents/views/multiple.py
vendored
Normal file
121
env/lib/python3.10/site-packages/wagtail/documents/views/multiple.py
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
import os.path
|
||||
|
||||
from wagtail.admin.views.generic.multiple_upload import AddView as BaseAddView
|
||||
from wagtail.admin.views.generic.multiple_upload import (
|
||||
CreateFromUploadView as BaseCreateFromUploadView,
|
||||
)
|
||||
from wagtail.admin.views.generic.multiple_upload import (
|
||||
DeleteUploadView as BaseDeleteUploadView,
|
||||
)
|
||||
from wagtail.admin.views.generic.multiple_upload import DeleteView as BaseDeleteView
|
||||
from wagtail.admin.views.generic.multiple_upload import EditView as BaseEditView
|
||||
|
||||
from .. import get_document_model
|
||||
from ..forms import get_document_form, get_document_multi_form
|
||||
from ..permissions import permission_policy
|
||||
|
||||
|
||||
class AddView(BaseAddView):
|
||||
permission_policy = permission_policy
|
||||
template_name = "wagtaildocs/multiple/add.html"
|
||||
|
||||
edit_object_url_name = "wagtaildocs:edit_multiple"
|
||||
delete_object_url_name = "wagtaildocs:delete_multiple"
|
||||
edit_object_form_prefix = "doc"
|
||||
context_object_name = "doc"
|
||||
context_object_id_name = "doc_id"
|
||||
|
||||
edit_upload_url_name = "wagtaildocs:create_multiple_from_uploaded_document"
|
||||
delete_upload_url_name = "wagtaildocs:delete_upload_multiple"
|
||||
edit_upload_form_prefix = "uploaded-document"
|
||||
context_upload_name = "uploaded_document"
|
||||
context_upload_id_name = "uploaded_file_id"
|
||||
|
||||
def get_model(self):
|
||||
return get_document_model()
|
||||
|
||||
def get_upload_form_class(self):
|
||||
return get_document_form(self.model)
|
||||
|
||||
def get_edit_form_class(self):
|
||||
return get_document_multi_form(self.model)
|
||||
|
||||
def save_object(self, form):
|
||||
doc = form.save(commit=False)
|
||||
doc.uploaded_by_user = self.request.user
|
||||
doc._set_document_file_metadata()
|
||||
doc.save()
|
||||
|
||||
return doc
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context.update(
|
||||
{
|
||||
"max_title_length": self.form.fields["title"].max_length,
|
||||
}
|
||||
)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class EditView(BaseEditView):
|
||||
permission_policy = permission_policy
|
||||
pk_url_kwarg = "doc_id"
|
||||
edit_object_form_prefix = "doc"
|
||||
context_object_name = "doc"
|
||||
context_object_id_name = "doc_id"
|
||||
edit_object_url_name = "wagtaildocs:edit_multiple"
|
||||
delete_object_url_name = "wagtaildocs:delete_multiple"
|
||||
|
||||
def get_model(self):
|
||||
return get_document_model()
|
||||
|
||||
def get_edit_form_class(self):
|
||||
return get_document_multi_form(self.model)
|
||||
|
||||
|
||||
class DeleteView(BaseDeleteView):
|
||||
permission_policy = permission_policy
|
||||
pk_url_kwarg = "doc_id"
|
||||
context_object_id_name = "doc_id"
|
||||
|
||||
def get_model(self):
|
||||
return get_document_model()
|
||||
|
||||
|
||||
class CreateFromUploadedDocumentView(BaseCreateFromUploadView):
|
||||
edit_upload_url_name = "wagtaildocs:create_multiple_from_uploaded_document"
|
||||
delete_upload_url_name = "wagtaildocs:delete_upload_multiple"
|
||||
upload_pk_url_kwarg = "uploaded_file_id"
|
||||
edit_upload_form_prefix = "uploaded-document"
|
||||
context_object_id_name = "doc_id"
|
||||
context_upload_name = "uploaded_document"
|
||||
|
||||
def get_model(self):
|
||||
return get_document_model()
|
||||
|
||||
def get_edit_form_class(self):
|
||||
return get_document_multi_form(self.model)
|
||||
|
||||
def save_object(self, form):
|
||||
# assign the file content from uploaded_doc to the image object, to ensure it gets saved to
|
||||
# Document's storage
|
||||
|
||||
self.object.file.save(
|
||||
os.path.basename(self.upload.file.name), self.upload.file.file, save=False
|
||||
)
|
||||
self.object.uploaded_by_user = self.request.user
|
||||
|
||||
# form.save() would normally handle writing the image file metadata, but in this case the
|
||||
# file handling happens outside the form, so we need to do that manually
|
||||
self.object._set_document_file_metadata()
|
||||
form.save()
|
||||
|
||||
|
||||
class DeleteUploadView(BaseDeleteUploadView):
|
||||
upload_pk_url_kwarg = "uploaded_file_id"
|
||||
|
||||
def get_model(self):
|
||||
return get_document_model()
|
||||
158
env/lib/python3.10/site-packages/wagtail/documents/views/serve.py
vendored
Normal file
158
env/lib/python3.10/site-packages/wagtail/documents/views/serve.py
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
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)
|
||||
|
||||
# We want to ensure that the document filename provided in the URL matches the one associated with the considered
|
||||
# document_id. If not we can't be sure that the document the user wants to access is the one corresponding to the
|
||||
# <document_id, document_filename> pair.
|
||||
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
|
||||
|
||||
# Send document_served signal
|
||||
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 no serve method has been specified, select an appropriate default for the storage backend:
|
||||
# redirect for remote storages (i.e. ones that provide a url but not a local path) and
|
||||
# serve_view for all other cases
|
||||
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:
|
||||
# Serve the file by redirecting to the URL provided by the underlying storage;
|
||||
# this saves the cost of delivering the file via Python.
|
||||
# For serve_method == 'direct', this view should not normally be reached
|
||||
# (the document URL as used in links should point directly to the storage URL instead)
|
||||
# but we handle it as a redirect to provide sensible fallback /
|
||||
# backwards compatibility behaviour.
|
||||
return redirect(direct_url)
|
||||
|
||||
if local_path:
|
||||
# Use wagtail.utils.sendfile to serve the file;
|
||||
# this provides support for mimetypes, if-modified-since and django-sendfile backends
|
||||
|
||||
sendfile_opts = {
|
||||
"attachment": (doc.content_disposition != "inline"),
|
||||
"attachment_filename": doc.filename,
|
||||
"mimetype": doc.content_type,
|
||||
}
|
||||
if not hasattr(settings, "SENDFILE_BACKEND"):
|
||||
# Fallback to streaming backend if user hasn't specified SENDFILE_BACKEND
|
||||
sendfile_opts["backend"] = sendfile_streaming_backend.sendfile
|
||||
|
||||
return sendfile(request, local_path, **sendfile_opts)
|
||||
|
||||
else:
|
||||
# We are using a storage backend which does not expose filesystem paths
|
||||
# (e.g. storages.backends.s3boto.S3BotoStorage) AND the developer has not allowed
|
||||
# redirecting to the file url directly.
|
||||
# Fall back on pre-sendfile behaviour of reading the file content and serving it
|
||||
# as a FileResponse
|
||||
response = FileResponse(doc.file, doc.content_type)
|
||||
|
||||
# set filename and filename* to handle non-ascii characters in filename
|
||||
# see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
||||
response["Content-Disposition"] = doc.content_disposition
|
||||
|
||||
# FIXME: storage backends are not guaranteed to implement 'size'
|
||||
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():
|
||||
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)
|
||||
Reference in New Issue
Block a user