Initial commit
This commit is contained in:
0
env/lib/python3.10/site-packages/wagtail/documents/tests/__init__.py
vendored
Normal file
0
env/lib/python3.10/site-packages/wagtail/documents/tests/__init__.py
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/__init__.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/__init__.cpython-310.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_blocks.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_blocks.cpython-310.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_models.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_models.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_rich_text.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_rich_text.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_search.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_search.cpython-310.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_views.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/test_views.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/utils.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/wagtail/documents/tests/__pycache__/utils.cpython-310.pyc
vendored
Normal file
Binary file not shown.
2297
env/lib/python3.10/site-packages/wagtail/documents/tests/test_admin_views.py
vendored
Normal file
2297
env/lib/python3.10/site-packages/wagtail/documents/tests/test_admin_views.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
30
env/lib/python3.10/site-packages/wagtail/documents/tests/test_blocks.py
vendored
Normal file
30
env/lib/python3.10/site-packages/wagtail/documents/tests/test_blocks.py
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
from django.test import TestCase
|
||||
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.documents.blocks import DocumentChooserBlock
|
||||
|
||||
from .utils import get_test_document_file
|
||||
|
||||
|
||||
class TestDocumentChooserBlock(TestCase):
|
||||
def test_deconstruct(self):
|
||||
block = DocumentChooserBlock(required=False)
|
||||
path, args, kwargs = block.deconstruct()
|
||||
self.assertEqual(path, "wagtail.documents.blocks.DocumentChooserBlock")
|
||||
self.assertEqual(args, ())
|
||||
self.assertEqual(kwargs, {"required": False})
|
||||
|
||||
def test_extract_references(self):
|
||||
Document = get_document_model()
|
||||
document = Document.objects.create(
|
||||
title="Test document", file=get_test_document_file()
|
||||
)
|
||||
block = DocumentChooserBlock()
|
||||
|
||||
self.assertListEqual(
|
||||
list(block.extract_references(document)),
|
||||
[(Document, str(document.id), "", "")],
|
||||
)
|
||||
|
||||
# None should not yield any references
|
||||
self.assertListEqual(list(block.extract_references(None)), [])
|
||||
0
env/lib/python3.10/site-packages/wagtail/documents/tests/test_bulk_actions/__init__.py
vendored
Normal file
0
env/lib/python3.10/site-packages/wagtail/documents/tests/test_bulk_actions/__init__.py
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
83
env/lib/python3.10/site-packages/wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py
vendored
Normal file
83
env/lib/python3.10/site-packages/wagtail/documents/tests/test_bulk_actions/test_bulk_add_tags.py
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
Document = get_document_model()
|
||||
|
||||
|
||||
def get_tag_list(document):
|
||||
return [tag.name for tag in document.tags.all()]
|
||||
|
||||
|
||||
class TestBulkAddTags(WagtailTestUtils, TestCase):
|
||||
def setUp(self):
|
||||
self.user = self.login()
|
||||
self.new_tags = ["first", "second"]
|
||||
self.documents = [
|
||||
Document.objects.create(title=f"Test document - {i}") for i in range(1, 6)
|
||||
]
|
||||
self.url = (
|
||||
reverse(
|
||||
"wagtail_bulk_action",
|
||||
args=(
|
||||
"wagtaildocs",
|
||||
"document",
|
||||
"add_tags",
|
||||
),
|
||||
)
|
||||
+ "?"
|
||||
)
|
||||
for document in self.documents:
|
||||
self.url += f"id={document.id}&"
|
||||
self.post_data = {"tags": ",".join(self.new_tags)}
|
||||
|
||||
def test_add_tags_with_limited_permissions(self):
|
||||
self.user.is_superuser = False
|
||||
self.user.user_permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type__app_label="wagtailadmin", codename="access_admin"
|
||||
)
|
||||
)
|
||||
self.user.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
html = response.content.decode()
|
||||
self.assertInHTML(
|
||||
"<p>You don't have permission to add tags to these documents</p>", html
|
||||
)
|
||||
|
||||
for document in self.documents:
|
||||
self.assertInHTML(f"<li>{document.title}</li>", html)
|
||||
|
||||
self.client.post(self.url, self.post_data)
|
||||
|
||||
# New tags should not be added to the documents
|
||||
for document in self.documents:
|
||||
self.assertCountEqual(
|
||||
get_tag_list(Document.objects.get(id=document.id)), []
|
||||
)
|
||||
|
||||
def test_simple(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
response, "wagtaildocs/bulk_actions/confirm_bulk_add_tags.html"
|
||||
)
|
||||
|
||||
def test_add_tags(self):
|
||||
# Make post request
|
||||
response = self.client.post(self.url, self.post_data)
|
||||
|
||||
# User should be redirected back to the index
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# New tags should not be added to the documents
|
||||
for document in self.documents:
|
||||
self.assertCountEqual(
|
||||
get_tag_list(Document.objects.get(id=document.id)), self.new_tags
|
||||
)
|
||||
@@ -0,0 +1,84 @@
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.models import Collection
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
Document = get_document_model()
|
||||
|
||||
|
||||
class TestBulkAddDocumentsToCollection(WagtailTestUtils, TestCase):
|
||||
def setUp(self):
|
||||
self.user = self.login()
|
||||
self.root_collection = Collection.get_first_root_node()
|
||||
self.dest_collection = self.root_collection.add_child(name="Destination")
|
||||
self.documents = [
|
||||
Document.objects.create(title=f"Test document - {i}") for i in range(1, 6)
|
||||
]
|
||||
self.url = (
|
||||
reverse(
|
||||
"wagtail_bulk_action",
|
||||
args=(
|
||||
"wagtaildocs",
|
||||
"document",
|
||||
"add_to_collection",
|
||||
),
|
||||
)
|
||||
+ "?"
|
||||
)
|
||||
for document in self.documents:
|
||||
self.url += f"id={document.id}&"
|
||||
self.post_data = {"collection": str(self.dest_collection.id)}
|
||||
|
||||
def test_add_to_collection_with_limited_permissions(self):
|
||||
self.user.is_superuser = False
|
||||
self.user.user_permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type__app_label="wagtailadmin", codename="access_admin"
|
||||
)
|
||||
)
|
||||
self.user.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
html = response.content.decode()
|
||||
self.assertInHTML(
|
||||
"<p>You don't have permission to add these documents to a collection</p>",
|
||||
html,
|
||||
)
|
||||
|
||||
for document in self.documents:
|
||||
self.assertInHTML(f"<li>{document.title}</li>", html)
|
||||
|
||||
self.client.post(self.url, self.post_data)
|
||||
|
||||
# Documents should not be moved to new collection
|
||||
for document in self.documents:
|
||||
self.assertEqual(
|
||||
Document.objects.get(id=document.id).collection_id,
|
||||
self.root_collection.id,
|
||||
)
|
||||
|
||||
def test_simple(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
response, "wagtaildocs/bulk_actions/confirm_bulk_add_to_collection.html"
|
||||
)
|
||||
|
||||
def test_add_to_collection(self):
|
||||
# Make post request
|
||||
response = self.client.post(self.url, self.post_data)
|
||||
|
||||
# User should be redirected back to the index
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# Documents should be moved to new collection
|
||||
for document in self.documents:
|
||||
self.assertEqual(
|
||||
Document.objects.get(id=document.id).collection_id,
|
||||
self.dest_collection.id,
|
||||
)
|
||||
88
env/lib/python3.10/site-packages/wagtail/documents/tests/test_bulk_actions/test_bulk_delete.py
vendored
Normal file
88
env/lib/python3.10/site-packages/wagtail/documents/tests/test_bulk_actions/test_bulk_delete.py
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
Document = get_document_model()
|
||||
|
||||
|
||||
class TestDocumentBulkDeleteView(WagtailTestUtils, TestCase):
|
||||
def setUp(self):
|
||||
self.user = self.login()
|
||||
|
||||
# Create documents to delete
|
||||
self.documents = [
|
||||
Document.objects.create(title=f"Test document - {i}") for i in range(1, 6)
|
||||
]
|
||||
self.url = (
|
||||
reverse(
|
||||
"wagtail_bulk_action",
|
||||
args=(
|
||||
"wagtaildocs",
|
||||
"document",
|
||||
"delete",
|
||||
),
|
||||
)
|
||||
+ "?"
|
||||
)
|
||||
for document in self.documents:
|
||||
self.url += f"id={document.id}&"
|
||||
|
||||
def test_delete_with_limited_permissions(self):
|
||||
self.user.is_superuser = False
|
||||
self.user.user_permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type__app_label="wagtailadmin", codename="access_admin"
|
||||
)
|
||||
)
|
||||
self.user.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
html = response.content.decode()
|
||||
self.assertInHTML(
|
||||
"<p>You don't have permission to delete these documents</p>", html
|
||||
)
|
||||
|
||||
for document in self.documents:
|
||||
self.assertInHTML(f"<li>{document.title}</li>", html)
|
||||
|
||||
response = self.client.post(self.url)
|
||||
# User should be redirected back to the index
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# Documents should not be deleted
|
||||
for document in self.documents:
|
||||
self.assertTrue(Document.objects.filter(id=document.id).exists())
|
||||
|
||||
def test_simple(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
response, "wagtaildocs/bulk_actions/confirm_bulk_delete.html"
|
||||
)
|
||||
|
||||
def test_delete(self):
|
||||
# Make post request
|
||||
response = self.client.post(self.url)
|
||||
|
||||
# User should be redirected back to the index
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# Documents should be deleted
|
||||
for document in self.documents:
|
||||
self.assertFalse(Document.objects.filter(id=document.id).exists())
|
||||
|
||||
def test_usage_link(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
response, "wagtaildocs/bulk_actions/confirm_bulk_delete.html"
|
||||
)
|
||||
for document in self.documents:
|
||||
self.assertContains(response, document.usage_url)
|
||||
# usage count should be printed for each document
|
||||
self.assertContains(response, "Used 0 times", count=5)
|
||||
189
env/lib/python3.10/site-packages/wagtail/documents/tests/test_collection_privacy.py
vendored
Normal file
189
env/lib/python3.10/site-packages/wagtail/documents/tests/test_collection_privacy.py
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.files.base import ContentFile
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents.models import Document
|
||||
from wagtail.models import Collection, CollectionViewRestriction
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
try:
|
||||
from urllib.parse import quote
|
||||
except ImportError:
|
||||
from urllib import quote
|
||||
|
||||
|
||||
class TestCollectionPrivacyDocument(WagtailTestUtils, TestCase):
|
||||
fixtures = ["test.json"]
|
||||
|
||||
def setUp(self):
|
||||
self.fake_file = ContentFile(b"A boring example document")
|
||||
self.fake_file.name = "test.txt"
|
||||
self.collection = Collection.objects.get(id=2)
|
||||
self.password_collection = Collection.objects.get(name="Password protected")
|
||||
self.login_collection = Collection.objects.get(name="Login protected")
|
||||
self.group_collection = Collection.objects.get(name="Group protected")
|
||||
self.view_restriction = CollectionViewRestriction.objects.get(
|
||||
collection=self.password_collection
|
||||
)
|
||||
self.event_editors_group = Group.objects.get(name="Event editors")
|
||||
|
||||
def get_document(self, collection):
|
||||
secret_document = Document.objects.create(
|
||||
title="Test document",
|
||||
file=self.fake_file,
|
||||
collection=collection,
|
||||
)
|
||||
url = reverse(
|
||||
"wagtaildocs_serve", args=(secret_document.id, secret_document.filename)
|
||||
)
|
||||
response = self.client.get(url)
|
||||
return response, quote(url)
|
||||
|
||||
def test_anonymous_user_must_authenticate(self):
|
||||
secret_document = Document.objects.create(
|
||||
title="Test document",
|
||||
file=self.fake_file,
|
||||
collection=self.password_collection,
|
||||
)
|
||||
doc_url = reverse(
|
||||
"wagtaildocs_serve", args=(secret_document.id, secret_document.filename)
|
||||
)
|
||||
response = self.client.get(doc_url)
|
||||
self.assertEqual(
|
||||
response.templates[0].name, "wagtaildocs/password_required.html"
|
||||
)
|
||||
|
||||
submit_url = reverse(
|
||||
"wagtaildocs_authenticate_with_password", args=[self.view_restriction.id]
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, '<form action="%s"' % submit_url)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<input id="id_return_url" name="return_url" type="hidden" value="{}" />'.format(
|
||||
doc_url
|
||||
),
|
||||
html=True,
|
||||
)
|
||||
|
||||
# posting the wrong password should redisplay the password page
|
||||
response = self.client.post(
|
||||
submit_url,
|
||||
{
|
||||
"password": "wrongpassword",
|
||||
"return_url": doc_url,
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
response.templates[0].name, "wagtaildocs/password_required.html"
|
||||
)
|
||||
self.assertContains(response, '<form action="%s"' % submit_url)
|
||||
|
||||
# posting the correct password should redirect back to return_url
|
||||
response = self.client.post(
|
||||
submit_url,
|
||||
{
|
||||
"password": "swordfish",
|
||||
"return_url": doc_url,
|
||||
},
|
||||
)
|
||||
self.assertRedirects(response, doc_url)
|
||||
|
||||
# now requests to the documents url should pass authentication
|
||||
self.client.get(doc_url)
|
||||
|
||||
self.client.logout()
|
||||
|
||||
# posting an invalid return_url will redirect to default login redirect
|
||||
with self.settings(LOGIN_REDIRECT_URL="/"):
|
||||
response = self.client.post(
|
||||
submit_url,
|
||||
{
|
||||
"password": "swordfish",
|
||||
"return_url": "https://invaliddomain.com",
|
||||
},
|
||||
)
|
||||
self.assertRedirects(response, "/")
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_PASSWORD_REQUIRED_TEMPLATE="tests/custom_docs_password_required.html"
|
||||
)
|
||||
def test_anonymous_user_must_authenticate_with_custom_password_required_template(
|
||||
self
|
||||
):
|
||||
secret_document = Document.objects.create(
|
||||
title="Test document",
|
||||
file=self.fake_file,
|
||||
collection=self.password_collection,
|
||||
)
|
||||
doc_url = reverse(
|
||||
"wagtaildocs_serve", args=(secret_document.id, secret_document.filename)
|
||||
)
|
||||
response = self.client.get(doc_url)
|
||||
self.assertNotEqual(
|
||||
response.templates[0].name, "wagtaildocs/password_required.html"
|
||||
)
|
||||
self.assertEqual(
|
||||
response.templates[0].name, "tests/custom_docs_password_required.html"
|
||||
)
|
||||
|
||||
def test_group_restriction_with_anonymous_user(self):
|
||||
response, url = self.get_document(self.group_collection)
|
||||
self.assertRedirects(response, f"/_util/login/?next={url}")
|
||||
|
||||
def test_group_restriction_with_unpermitted_user(self):
|
||||
self.login(username="eventmoderator", password="password")
|
||||
response, url = self.get_document(self.group_collection)
|
||||
self.assertRedirects(response, f"/_util/login/?next={url}")
|
||||
|
||||
def test_group_restriction_with_permitted_user(self):
|
||||
self.login(username="eventeditor", password="password")
|
||||
response, url = self.get_document(self.group_collection)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_group_restriction_with_superuser(self):
|
||||
self.login(username="superuser", password="password")
|
||||
response, url = self.get_document(self.group_collection)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_login_restriction_with_anonymous_user(self):
|
||||
response, url = self.get_document(self.login_collection)
|
||||
self.assertRedirects(response, f"/_util/login/?next={url}")
|
||||
|
||||
def test_login_restriction_with_logged_in_user(self):
|
||||
self.login(username="eventmoderator", password="password")
|
||||
response, url = self.get_document(self.login_collection)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_set_shared_password_with_logged_in_user(self):
|
||||
self.login()
|
||||
response = self.client.get(
|
||||
reverse("wagtailadmin_collections:set_privacy", args=(self.collection.id,)),
|
||||
)
|
||||
|
||||
input_el = self.get_soup(response.content).select_one("[data-field-input]")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# check that input option for password is visible
|
||||
self.assertIn("password", response.context["form"].fields)
|
||||
|
||||
# check that the option for password is visible
|
||||
self.assertIsNotNone(input_el)
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_PRIVATE_COLLECTION_OPTIONS={"SHARED_PASSWORD": False}
|
||||
)
|
||||
def test_unset_shared_password_with_logged_in_user(self):
|
||||
self.login()
|
||||
response = self.client.get(
|
||||
reverse("wagtailadmin_collections:set_privacy", args=(self.collection.id,)),
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotIn("password", response.context["form"].fields)
|
||||
self.assertFalse(
|
||||
response.context["form"]
|
||||
.fields["restriction_type"]
|
||||
.valid_value(CollectionViewRestriction.PASSWORD)
|
||||
)
|
||||
280
env/lib/python3.10/site-packages/wagtail/documents/tests/test_document_chooser.py
vendored
Normal file
280
env/lib/python3.10/site-packages/wagtail/documents/tests/test_document_chooser.py
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents.models import Document
|
||||
from wagtail.models import (
|
||||
Collection,
|
||||
GroupCollectionPermission,
|
||||
Page,
|
||||
get_root_collection_id,
|
||||
)
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
|
||||
class TestChooser(WagtailTestUtils, TestCase):
|
||||
"""Test chooser panel rendered by `wagtaildocs_chooser:choose` view"""
|
||||
|
||||
_NO_DOCS_TEXT = "You haven't uploaded any documents."
|
||||
_NO_COLLECTION_DOCS_TEXT = "You haven't uploaded any documents in this collection."
|
||||
_UPLOAD_ONE_TEXT = "upload one now" # text from the link that opens upload form
|
||||
|
||||
def setUp(self):
|
||||
self.root_page = Page.objects.get(id=2)
|
||||
|
||||
def login_as_superuser(self):
|
||||
self.login()
|
||||
|
||||
def login_as_editor(self):
|
||||
# Create group with access to admin
|
||||
editors_group = Group.objects.create(name="The Editors")
|
||||
access_admin_perm = Permission.objects.get(
|
||||
content_type__app_label="wagtailadmin", codename="access_admin"
|
||||
)
|
||||
editors_group.permissions.add(access_admin_perm)
|
||||
# Grant "choose" permission to the Editors group on the Root Collection.
|
||||
choose_document_permission = Permission.objects.get(
|
||||
content_type__app_label="wagtaildocs", codename="choose_document"
|
||||
)
|
||||
GroupCollectionPermission.objects.create(
|
||||
group=editors_group,
|
||||
collection=Collection.objects.get(depth=1),
|
||||
permission=choose_document_permission,
|
||||
)
|
||||
|
||||
# Create a non-superuser editor
|
||||
user = self.create_user(username="editor", password="password")
|
||||
user.groups.add(editors_group)
|
||||
|
||||
# Log in as a non-superuser editor
|
||||
self.login(user)
|
||||
|
||||
def login_as_baker(self):
|
||||
# Create group with access to admin and Chooser permission on one Collection, but not another.
|
||||
bakers_group = Group.objects.create(name="Bakers")
|
||||
access_admin_perm = Permission.objects.get(
|
||||
content_type__app_label="wagtailadmin", codename="access_admin"
|
||||
)
|
||||
bakers_group.permissions.add(access_admin_perm)
|
||||
# Create the "Bakery" Collection and grant "choose" permission to the Bakers group.
|
||||
root = Collection.objects.get(id=get_root_collection_id())
|
||||
bakery_collection = root.add_child(instance=Collection(name="Bakery"))
|
||||
GroupCollectionPermission.objects.create(
|
||||
group=bakers_group,
|
||||
collection=bakery_collection,
|
||||
permission=Permission.objects.get(
|
||||
content_type__app_label="wagtaildocs", codename="choose_document"
|
||||
),
|
||||
)
|
||||
# Create the "Office" Collection and _don't_ grant any permissions to the Bakers group.
|
||||
root.add_child(instance=Collection(name="Office"))
|
||||
|
||||
# Create a Baker user.
|
||||
user = self.create_user(username="baker", password="password")
|
||||
user.groups.add(bakers_group)
|
||||
|
||||
# Log in as the baker.
|
||||
self.login(user)
|
||||
|
||||
def get(self, params=None):
|
||||
return self.client.get(reverse("wagtaildocs_chooser:choose"), params or {})
|
||||
|
||||
def test_chooser_docs_exist(self):
|
||||
# given an editor with access to admin panel
|
||||
self.login_as_editor()
|
||||
# and a document in the database
|
||||
doc_title = "document.pdf"
|
||||
Document.objects.create(title=doc_title)
|
||||
|
||||
# when opening chooser
|
||||
response = self.get()
|
||||
|
||||
# then chooser template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailadmin/generic/chooser/chooser.html")
|
||||
# and document is displayed
|
||||
self.assertContains(response, doc_title)
|
||||
# and no hints are displayed
|
||||
self.assertNotContains(response, self._NO_DOCS_TEXT)
|
||||
self.assertNotContains(response, self._NO_COLLECTION_DOCS_TEXT)
|
||||
self.assertNotContains(response, self._UPLOAD_ONE_TEXT)
|
||||
|
||||
def test_chooser_only_docs_in_chooseable_collection_appear(self):
|
||||
# Log in as a baker, who has choose permission on the Bakery but not the Office.
|
||||
self.login_as_baker()
|
||||
# And a document to the Bakery and to the Office.
|
||||
bun_recipe_title = "bun_recipe.pdf"
|
||||
Document.objects.create(
|
||||
title=bun_recipe_title, collection=Collection.objects.get(name="Bakery")
|
||||
)
|
||||
payroll_title = "payroll.xlsx"
|
||||
Document.objects.create(
|
||||
title=payroll_title, collection=Collection.objects.get(name="Office")
|
||||
)
|
||||
|
||||
# Open the doc chooser.
|
||||
response = self.get()
|
||||
|
||||
# Confirm that the chooser opened successfully.
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailadmin/generic/chooser/chooser.html")
|
||||
# Ensure that the bun recipe is visible, but the payroll is not.
|
||||
self.assertContains(response, bun_recipe_title)
|
||||
self.assertNotContains(response, payroll_title)
|
||||
|
||||
def test_chooser_collection_selector_appears_only_if_multiple_collections_are_choosable(
|
||||
self,
|
||||
):
|
||||
# Log in as a baker, who has choose permission on the Bakery but not the Office.
|
||||
self.login_as_baker()
|
||||
|
||||
# Open the doc chooser.
|
||||
response = self.get()
|
||||
|
||||
# Confirm that the chooser opened successfully.
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailadmin/generic/chooser/chooser.html")
|
||||
# Ensure that the Collection chooser is not visible, because the Baker cannot
|
||||
# choose from multiple Collections.
|
||||
self.assertNotContains(response, "Collection")
|
||||
|
||||
# Let the Baker choose from the Office Collection.
|
||||
GroupCollectionPermission.objects.create(
|
||||
group=Group.objects.get(name="Bakers"),
|
||||
collection=Collection.objects.get(name="Office"),
|
||||
permission=Permission.objects.get(
|
||||
content_type__app_label="wagtaildocs", codename="choose_document"
|
||||
),
|
||||
)
|
||||
|
||||
# Open the doc chooser again.
|
||||
response = self.get()
|
||||
|
||||
# Confirm that the chooser opened successfully.
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailadmin/generic/chooser/chooser.html")
|
||||
# Ensure that the Collection chooser IS visible, because the Baker can now
|
||||
# choose from multiple Collections.
|
||||
self.assertContains(response, "Collection")
|
||||
|
||||
def test_chooser_no_docs_upload_allowed(self):
|
||||
# given a superuser and no documents in the database
|
||||
self.login_as_superuser()
|
||||
|
||||
# when opening chooser
|
||||
response = self.get()
|
||||
|
||||
# then chooser template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailadmin/generic/chooser/chooser.html")
|
||||
# and hint "You haven't uploaded any documents. Why not upload one now?" is displayed
|
||||
self.assertContains(response, self._NO_DOCS_TEXT)
|
||||
self.assertContains(response, self._UPLOAD_ONE_TEXT)
|
||||
|
||||
def test_chooser_no_docs_upload_forbidden(self):
|
||||
# given an editor with access to admin panel
|
||||
# and no documents in the database
|
||||
self.login_as_editor()
|
||||
|
||||
# when opening chooser
|
||||
response = self.get()
|
||||
|
||||
# then chooser template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtailadmin/generic/chooser/chooser.html")
|
||||
# and the following hint is displayed:
|
||||
# "You haven't uploaded any documents in this collection. Why not upload one now?"
|
||||
self.assertContains(response, self._NO_DOCS_TEXT)
|
||||
self.assertNotContains(response, self._UPLOAD_ONE_TEXT)
|
||||
|
||||
def test_results_docs_exist(self):
|
||||
# given a superuser
|
||||
self.login_as_superuser()
|
||||
# and a document in the database
|
||||
doc_title = "document.pdf"
|
||||
Document.objects.create(title=doc_title)
|
||||
|
||||
# when searching for any documents at chooser panel
|
||||
response = self.get({"q": ""})
|
||||
|
||||
# then results template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtaildocs/chooser/results.html")
|
||||
# and document is displayed
|
||||
self.assertContains(response, doc_title)
|
||||
# and no hints are displayed
|
||||
self.assertNotContains(response, self._NO_DOCS_TEXT)
|
||||
self.assertNotContains(response, self._NO_COLLECTION_DOCS_TEXT)
|
||||
self.assertNotContains(response, self._UPLOAD_ONE_TEXT)
|
||||
|
||||
def test_results_no_docs_upload_allowed(self):
|
||||
# given a superuser and no documents in the database
|
||||
self.login_as_superuser()
|
||||
|
||||
# when searching for any documents at chooser panel
|
||||
response = self.get({"q": ""})
|
||||
|
||||
# then results template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtaildocs/chooser/results.html")
|
||||
# and hint "You haven't uploaded any documents. Why not upload one now?" is displayed
|
||||
self.assertContains(response, self._NO_DOCS_TEXT)
|
||||
self.assertContains(response, self._UPLOAD_ONE_TEXT)
|
||||
|
||||
def test_results_no_docs_upload_forbidden(self):
|
||||
# given an editor with access to admin panel
|
||||
# and no documents in the database
|
||||
self.login_as_editor()
|
||||
|
||||
# when searching for any documents at chooser panel
|
||||
response = self.get({"q": ""})
|
||||
|
||||
# then results template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtaildocs/chooser/results.html")
|
||||
# and hint "You haven't uploaded any documents." is displayed
|
||||
self.assertContains(response, self._NO_DOCS_TEXT)
|
||||
self.assertNotContains(response, self._UPLOAD_ONE_TEXT)
|
||||
|
||||
def test_results_no_collection_docs_upload_allowed(self):
|
||||
# given a superuser
|
||||
self.login_as_superuser()
|
||||
# and a document in a collection
|
||||
root_id = get_root_collection_id()
|
||||
root = Collection.objects.get(id=root_id)
|
||||
empty_collection = Collection(name="Nothing to see here")
|
||||
root.add_child(instance=empty_collection)
|
||||
|
||||
doc_title = "document.pdf"
|
||||
Document.objects.create(title=doc_title, collection=root)
|
||||
|
||||
# when searching for documents in another collection at chooser panel
|
||||
response = self.get({"q": "", "collection_id": empty_collection.id})
|
||||
|
||||
# then results template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtaildocs/chooser/results.html")
|
||||
# and the following hint is displayed:
|
||||
# "You haven't uploaded any documents in this collection. Why not upload one now?"
|
||||
self.assertContains(response, self._NO_COLLECTION_DOCS_TEXT)
|
||||
self.assertContains(response, self._UPLOAD_ONE_TEXT)
|
||||
|
||||
def test_results_no_collection_docs_upload_forbidden(self):
|
||||
# given an editor with access to admin panel
|
||||
self.login_as_editor()
|
||||
# and a document in a collection
|
||||
root_id = get_root_collection_id()
|
||||
root = Collection.objects.get(id=root_id)
|
||||
empty_collection = Collection(name="Nothing to see here")
|
||||
root.add_child(instance=empty_collection)
|
||||
Document.objects.create(collection=root)
|
||||
|
||||
# when searching for documents in another collection at chooser panel
|
||||
response = self.get({"q": "", "collection_id": empty_collection.id})
|
||||
|
||||
# then results template is used
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "wagtaildocs/chooser/results.html")
|
||||
# and hint "You haven't uploaded any documents in this collection." is displayed
|
||||
self.assertContains(response, self._NO_COLLECTION_DOCS_TEXT)
|
||||
self.assertNotContains(response, self._UPLOAD_ONE_TEXT)
|
||||
95
env/lib/python3.10/site-packages/wagtail/documents/tests/test_form_overrides.py
vendored
Normal file
95
env/lib/python3.10/site-packages/wagtail/documents/tests/test_form_overrides.py
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
from django import forms
|
||||
from django.test import TestCase, override_settings
|
||||
from taggit import models as taggit_models
|
||||
|
||||
from wagtail.admin import widgets
|
||||
from wagtail.admin.widgets import AdminDateTimeInput
|
||||
from wagtail.documents import models
|
||||
from wagtail.documents.forms import (
|
||||
BaseDocumentForm,
|
||||
get_document_base_form,
|
||||
get_document_form,
|
||||
get_document_multi_form,
|
||||
)
|
||||
from wagtail.test.testapp.media_forms import AlternateDocumentForm, OverriddenWidget
|
||||
from wagtail.test.testapp.models import CustomRestaurantDocument, RestaurantTag
|
||||
|
||||
|
||||
class TestDocumentFormOverride(TestCase):
|
||||
def test_get_document_base_form(self):
|
||||
self.assertIs(get_document_base_form(), BaseDocumentForm)
|
||||
|
||||
def test_get_document_form(self):
|
||||
bases = get_document_form(models.Document).__bases__
|
||||
self.assertIn(BaseDocumentForm, bases)
|
||||
self.assertNotIn(AlternateDocumentForm, bases)
|
||||
|
||||
def test_get_document_form_widgets(self):
|
||||
form_cls = get_document_form(models.Document)
|
||||
form = form_cls()
|
||||
self.assertIsInstance(form.fields["tags"].widget, widgets.AdminTagWidget)
|
||||
self.assertEqual(form.fields["tags"].widget.tag_model, taggit_models.Tag)
|
||||
self.assertIsInstance(form.fields["file"].widget, forms.FileInput)
|
||||
|
||||
def test_tags_widget_with_custom_tag_model(self):
|
||||
form_cls = get_document_form(CustomRestaurantDocument)
|
||||
form = form_cls()
|
||||
self.assertIsInstance(form.fields["tags"].widget, widgets.AdminTagWidget)
|
||||
self.assertEqual(form.fields["tags"].widget.tag_model, RestaurantTag)
|
||||
|
||||
def test_tags_longer_than_max_characters(self):
|
||||
long_value = "longtag" * 20
|
||||
|
||||
form_data = {
|
||||
"title": "Test Document",
|
||||
"file": OverriddenWidget,
|
||||
"tags": [long_value],
|
||||
}
|
||||
|
||||
form_cls = get_document_form(models.Document)
|
||||
form = form_cls(form_data)
|
||||
|
||||
self.assertFalse(form.is_valid())
|
||||
self.assertIn("tags", form.errors)
|
||||
self.assertEqual(
|
||||
form.errors["tags"][0],
|
||||
"Tag(s) ['{val}'] are over {max_tag_length} characters".format(
|
||||
val=long_value,
|
||||
max_tag_length=taggit_models.TagBase._meta.get_field("name").max_length,
|
||||
),
|
||||
)
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_DOCUMENT_FORM_BASE="wagtail.test.testapp.media_forms.AlternateDocumentForm"
|
||||
)
|
||||
def test_overridden_base_form(self):
|
||||
self.assertIs(get_document_base_form(), AlternateDocumentForm)
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_DOCUMENT_FORM_BASE="wagtail.test.testapp.media_forms.AlternateDocumentForm"
|
||||
)
|
||||
def test_get_overridden_document_form(self):
|
||||
bases = get_document_form(models.Document).__bases__
|
||||
self.assertNotIn(BaseDocumentForm, bases)
|
||||
self.assertIn(AlternateDocumentForm, bases)
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_DOCUMENT_FORM_BASE="wagtail.test.testapp.media_forms.AlternateDocumentForm"
|
||||
)
|
||||
def test_get_overridden_document_multi_form(self):
|
||||
bases = get_document_multi_form(models.Document).__bases__
|
||||
self.assertNotIn(BaseDocumentForm, bases)
|
||||
self.assertIn(AlternateDocumentForm, bases)
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_DOCUMENT_FORM_BASE="wagtail.test.testapp.media_forms.AlternateDocumentForm"
|
||||
)
|
||||
def test_get_overridden_document_form_widgets(self):
|
||||
form_cls = get_document_form(models.Document)
|
||||
form = form_cls()
|
||||
|
||||
self.assertIsInstance(form.fields["tags"].widget, OverriddenWidget)
|
||||
self.assertIsInstance(form.fields["file"].widget, OverriddenWidget)
|
||||
|
||||
self.assertIn("form_only_field", form.fields)
|
||||
self.assertIs(form.Meta.widgets["form_only_field"], AdminDateTimeInput)
|
||||
310
env/lib/python3.10/site-packages/wagtail/documents/tests/test_models.py
vendored
Normal file
310
env/lib/python3.10/site-packages/wagtail/documents/tests/test_models.py
vendored
Normal file
@@ -0,0 +1,310 @@
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
||||
from django.core.files.base import ContentFile
|
||||
from django.db import transaction
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from wagtail.documents import (
|
||||
get_document_model,
|
||||
get_document_model_string,
|
||||
models,
|
||||
signal_handlers,
|
||||
)
|
||||
from wagtail.images.tests.utils import get_test_image_file
|
||||
from wagtail.models import Collection, GroupCollectionPermission
|
||||
from wagtail.test.testapp.models import CustomDocument, ReimportedDocumentModel
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
|
||||
class TestDocumentQuerySet(TransactionTestCase):
|
||||
fixtures = ["test_empty.json"]
|
||||
|
||||
def test_search_method(self):
|
||||
# Make a test document
|
||||
document = models.Document.objects.create(title="Test document")
|
||||
|
||||
# Search for it
|
||||
results = models.Document.objects.search("Test")
|
||||
self.assertEqual(list(results), [document])
|
||||
|
||||
def test_operators(self):
|
||||
aaa_document = models.Document.objects.create(title="AAA Test document")
|
||||
zzz_document = models.Document.objects.create(title="ZZZ Test document")
|
||||
|
||||
results = models.Document.objects.search("aaa test", operator="and")
|
||||
self.assertEqual(list(results), [aaa_document])
|
||||
|
||||
results = models.Document.objects.search("aaa test", operator="or")
|
||||
sorted_results = sorted(results, key=lambda doc: doc.title)
|
||||
self.assertEqual(sorted_results, [aaa_document, zzz_document])
|
||||
|
||||
def test_custom_ordering(self):
|
||||
aaa_document = models.Document.objects.create(title="AAA Test document")
|
||||
zzz_document = models.Document.objects.create(title="ZZZ Test document")
|
||||
|
||||
results = models.Document.objects.order_by("title").search(
|
||||
"Test", order_by_relevance=False
|
||||
)
|
||||
self.assertEqual(list(results), [aaa_document, zzz_document])
|
||||
results = models.Document.objects.order_by("-title").search(
|
||||
"Test", order_by_relevance=False
|
||||
)
|
||||
self.assertEqual(list(results), [zzz_document, aaa_document])
|
||||
|
||||
|
||||
class TestDocumentPermissions(WagtailTestUtils, TestCase):
|
||||
def setUp(self):
|
||||
# Create some user accounts for testing permissions
|
||||
self.user = self.create_user(
|
||||
username="user", email="user@email.com", password="password"
|
||||
)
|
||||
self.owner = self.create_user(
|
||||
username="owner", email="owner@email.com", password="password"
|
||||
)
|
||||
self.editor = self.create_user(
|
||||
username="editor", email="editor@email.com", password="password"
|
||||
)
|
||||
self.editor.groups.add(Group.objects.get(name="Editors"))
|
||||
self.administrator = self.create_superuser(
|
||||
username="administrator",
|
||||
email="administrator@email.com",
|
||||
password="password",
|
||||
)
|
||||
|
||||
# Owner user must have the add_document permission
|
||||
self.adders_group = Group.objects.create(name="Document adders")
|
||||
GroupCollectionPermission.objects.create(
|
||||
group=self.adders_group,
|
||||
collection=Collection.get_first_root_node(),
|
||||
permission=Permission.objects.get(codename="add_document"),
|
||||
)
|
||||
self.owner.groups.add(self.adders_group)
|
||||
|
||||
# Create a document for running tests on
|
||||
self.document = models.Document.objects.create(
|
||||
title="Test document", uploaded_by_user=self.owner
|
||||
)
|
||||
|
||||
def test_administrator_can_edit(self):
|
||||
self.assertTrue(self.document.is_editable_by_user(self.administrator))
|
||||
|
||||
def test_editor_can_edit(self):
|
||||
self.assertTrue(self.document.is_editable_by_user(self.editor))
|
||||
|
||||
def test_owner_can_edit(self):
|
||||
self.assertTrue(self.document.is_editable_by_user(self.owner))
|
||||
|
||||
def test_user_cant_edit(self):
|
||||
self.assertFalse(self.document.is_editable_by_user(self.user))
|
||||
|
||||
|
||||
class TestDocumentFilenameProperties(TestCase):
|
||||
def setUp(self):
|
||||
self.document = models.Document(title="Test document")
|
||||
self.document.file.save(
|
||||
"sample_name.doc",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
|
||||
self.pdf_document = models.Document(title="Test document")
|
||||
self.pdf_document.file.save(
|
||||
"sample_name.pdf",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
|
||||
self.extensionless_document = models.Document(title="Test document")
|
||||
self.extensionless_document.file.save(
|
||||
"sample_name",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
|
||||
def test_filename(self):
|
||||
self.assertEqual("sample_name.doc", self.document.filename)
|
||||
self.assertEqual("sample_name.pdf", self.pdf_document.filename)
|
||||
self.assertEqual("sample_name", self.extensionless_document.filename)
|
||||
|
||||
def test_file_extension(self):
|
||||
self.assertEqual("doc", self.document.file_extension)
|
||||
self.assertEqual("pdf", self.pdf_document.file_extension)
|
||||
self.assertEqual("", self.extensionless_document.file_extension)
|
||||
|
||||
def test_content_type(self):
|
||||
self.assertEqual("application/msword", self.document.content_type)
|
||||
self.assertEqual("application/pdf", self.pdf_document.content_type)
|
||||
self.assertEqual(
|
||||
"application/octet-stream", self.extensionless_document.content_type
|
||||
)
|
||||
|
||||
def test_file_hash(self):
|
||||
self.assertEqual(
|
||||
self.document.get_file_hash(), "7d8c4778b182e4f3bd442408c64a6e22a4b0ed85"
|
||||
)
|
||||
self.assertEqual(
|
||||
self.pdf_document.get_file_hash(),
|
||||
"7d8c4778b182e4f3bd442408c64a6e22a4b0ed85",
|
||||
)
|
||||
self.assertEqual(
|
||||
self.extensionless_document.get_file_hash(),
|
||||
"7d8c4778b182e4f3bd442408c64a6e22a4b0ed85",
|
||||
)
|
||||
|
||||
def test_content_disposition(self):
|
||||
self.assertEqual(
|
||||
"""attachment; filename=sample_name.doc; filename*=UTF-8''sample_name.doc""",
|
||||
self.document.content_disposition,
|
||||
)
|
||||
self.assertEqual("inline", self.pdf_document.content_disposition)
|
||||
self.assertEqual(
|
||||
"""attachment; filename=sample_name; filename*=UTF-8''sample_name""",
|
||||
self.extensionless_document.content_disposition,
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
# delete the FieldFile directly because the TestCase does not commit
|
||||
# transactions to trigger transaction.on_commit() in the signal handler
|
||||
self.document.file.delete()
|
||||
self.pdf_document.file.delete()
|
||||
self.extensionless_document.file.delete()
|
||||
|
||||
|
||||
class TestFilesDeletedForDefaultModels(TransactionTestCase):
|
||||
"""
|
||||
Because we expect file deletion to only happen once a transaction is
|
||||
successfully committed, we must run these tests using TransactionTestCase
|
||||
per the following documentation:
|
||||
|
||||
Django's TestCase class wraps each test in a transaction and rolls back that
|
||||
transaction after each test, in order to provide test isolation. This means
|
||||
that no transaction is ever actually committed, thus your on_commit()
|
||||
callbacks will never be run. If you need to test the results of an
|
||||
on_commit() callback, use a TransactionTestCase instead.
|
||||
https://docs.djangoproject.com/en/1.10/topics/db/transactions/#use-in-tests
|
||||
"""
|
||||
|
||||
fixtures = ["test_empty.json"]
|
||||
|
||||
def test_document_file_deleted_oncommit(self):
|
||||
with transaction.atomic():
|
||||
document = get_document_model().objects.create(
|
||||
title="Test Image", file=get_test_image_file()
|
||||
)
|
||||
filename = document.file.name
|
||||
|
||||
self.assertTrue(document.file.storage.exists(filename))
|
||||
document.delete()
|
||||
self.assertTrue(document.file.storage.exists(filename))
|
||||
self.assertFalse(document.file.storage.exists(filename))
|
||||
|
||||
|
||||
@override_settings(WAGTAILDOCS_EXTENSIONS=["pdf"])
|
||||
class TestDocumentValidateExtensions(TestCase):
|
||||
def setUp(self):
|
||||
self.document_invalid = models.Document.objects.create(
|
||||
title="Test document", file="test.doc"
|
||||
)
|
||||
self.document_valid = models.Document.objects.create(
|
||||
title="Test document", file="test.pdf"
|
||||
)
|
||||
|
||||
def test_create_doc_invalid_extension(self):
|
||||
"""
|
||||
Checks if the uploaded document has the expected extensions
|
||||
mentioned in settings.WAGTAILDOCS_EXTENSIONS
|
||||
|
||||
This is caught in form.error and should be raised during model
|
||||
creation when called full_clean. This specific testcase invalid
|
||||
file extension is passed
|
||||
"""
|
||||
with self.assertRaises(ValidationError) as e:
|
||||
self.document_invalid.full_clean()
|
||||
expected_message = (
|
||||
"File extension “doc” is not allowed. Allowed extensions are: pdf."
|
||||
)
|
||||
self.assertEqual(e.exception.message_dict["file"][0], expected_message)
|
||||
|
||||
def test_create_doc_valid_extension(self):
|
||||
"""
|
||||
Checks if the uploaded document has the expected extensions
|
||||
mentioned in settings.WAGTAILDOCS_EXTENSIONS
|
||||
|
||||
This is caught in form.error and should be raised during
|
||||
model creation when called full_clean. In this specific
|
||||
testcase invalid file extension is passed.
|
||||
"""
|
||||
try:
|
||||
self.document_valid.full_clean()
|
||||
except ValidationError:
|
||||
self.fail("Validation error is raised even when valid file name is passed")
|
||||
|
||||
def tearDown(self):
|
||||
self.document_invalid.file.delete()
|
||||
self.document_valid.file.delete()
|
||||
|
||||
|
||||
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.CustomDocument")
|
||||
class TestFilesDeletedForCustomModels(TestFilesDeletedForDefaultModels):
|
||||
def setUp(self):
|
||||
# Required to create root collection because the TransactionTestCase
|
||||
# does not make initial data loaded in migrations available and
|
||||
# serialized_rollback=True causes other problems in the test suite.
|
||||
# ref: https://docs.djangoproject.com/en/1.10/topics/testing/overview/#rollback-emulation
|
||||
Collection.objects.get_or_create(
|
||||
name="Root",
|
||||
path="0001",
|
||||
depth=1,
|
||||
numchild=0,
|
||||
)
|
||||
|
||||
#: Sadly signal receivers only get connected when starting django.
|
||||
#: We will re-attach them here to mimic the django startup behaviour
|
||||
#: and get the signals connected to our custom model..
|
||||
signal_handlers.register_signal_handlers()
|
||||
|
||||
def test_document_model(self):
|
||||
cls = get_document_model()
|
||||
self.assertEqual(
|
||||
f"{cls._meta.app_label}.{cls.__name__}", "tests.CustomDocument"
|
||||
)
|
||||
|
||||
|
||||
class TestGetDocumentModel(WagtailTestUtils, TestCase):
|
||||
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.CustomDocument")
|
||||
def test_custom_get_document_model(self):
|
||||
"""Test get_document_model with a custom document model"""
|
||||
self.assertIs(get_document_model(), CustomDocument)
|
||||
|
||||
def test_get_document_model_at_import_time(self):
|
||||
self.assertEqual(ReimportedDocumentModel, models.Document)
|
||||
|
||||
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.CustomDocument")
|
||||
def test_custom_get_document_model_string(self):
|
||||
"""Test get_document_model_string with a custom document model"""
|
||||
self.assertEqual(get_document_model_string(), "tests.CustomDocument")
|
||||
|
||||
@override_settings()
|
||||
def test_standard_get_document_model(self):
|
||||
"""Test get_document_model with no WAGTAILDOCS_DOCUMENT_MODEL"""
|
||||
del settings.WAGTAILDOCS_DOCUMENT_MODEL
|
||||
from wagtail.documents.models import Document
|
||||
|
||||
self.assertIs(get_document_model(), Document)
|
||||
|
||||
@override_settings()
|
||||
def test_standard_get_document_model_string(self):
|
||||
"""Test get_document_model_string with no WAGTAILDOCS_DOCUMENT_MODEL"""
|
||||
del settings.WAGTAILDOCS_DOCUMENT_MODEL
|
||||
self.assertEqual(get_document_model_string(), "wagtaildocs.Document")
|
||||
|
||||
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.UnknownModel")
|
||||
def test_unknown_get_document_model(self):
|
||||
"""Test get_document_model with an unknown model"""
|
||||
with self.assertRaises(ImproperlyConfigured):
|
||||
get_document_model()
|
||||
|
||||
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="invalid-string")
|
||||
def test_invalid_get_document_model(self):
|
||||
"""Test get_document_model with an invalid model string"""
|
||||
with self.assertRaises(ImproperlyConfigured):
|
||||
get_document_model()
|
||||
76
env/lib/python3.10/site-packages/wagtail/documents/tests/test_rich_text.py
vendored
Normal file
76
env/lib/python3.10/site-packages/wagtail/documents/tests/test_rich_text.py
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.documents.rich_text import (
|
||||
DocumentLinkHandler as FrontendDocumentLinkHandler,
|
||||
)
|
||||
from wagtail.documents.rich_text.editor_html import (
|
||||
DocumentLinkHandler as EditorHtmlDocumentLinkHandler,
|
||||
)
|
||||
from wagtail.fields import RichTextField
|
||||
from wagtail.rich_text.feature_registry import FeatureRegistry
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
|
||||
class TestEditorHtmlDocumentLinkHandler(WagtailTestUtils, TestCase):
|
||||
fixtures = ["test.json"]
|
||||
|
||||
def test_get_db_attributes(self):
|
||||
soup = self.get_soup('<a data-id="test-id">foo</a>')
|
||||
tag = soup.a
|
||||
result = EditorHtmlDocumentLinkHandler.get_db_attributes(tag)
|
||||
self.assertEqual(result, {"id": "test-id"})
|
||||
|
||||
def test_expand_db_attributes_for_editor(self):
|
||||
result = EditorHtmlDocumentLinkHandler.expand_db_attributes({"id": 1})
|
||||
self.assertEqual(
|
||||
result,
|
||||
'<a data-linktype="document" data-id="1" href="/documents/1/test.pdf">',
|
||||
)
|
||||
|
||||
def test_expand_db_attributes_for_editor_preserves_id_of_nonexistent_document(self):
|
||||
result = EditorHtmlDocumentLinkHandler.expand_db_attributes({"id": 0})
|
||||
self.assertEqual(result, '<a data-linktype="document" data-id="0">')
|
||||
|
||||
def test_expand_db_attributes_for_editor_with_missing_id(self):
|
||||
result = EditorHtmlDocumentLinkHandler.expand_db_attributes({})
|
||||
self.assertEqual(result, '<a data-linktype="document">')
|
||||
|
||||
|
||||
class TestFrontendDocumentLinkHandler(TestCase):
|
||||
fixtures = ["test.json"]
|
||||
|
||||
def test_expand_db_attributes_for_frontend(self):
|
||||
result = FrontendDocumentLinkHandler.expand_db_attributes({"id": 1})
|
||||
self.assertEqual(result, '<a href="/documents/1/test.pdf">')
|
||||
|
||||
def test_expand_db_attributes_document_does_not_exist(self):
|
||||
result = FrontendDocumentLinkHandler.expand_db_attributes({"id": 0})
|
||||
self.assertEqual(result, "<a>")
|
||||
|
||||
def test_expand_db_attributes_with_missing_id(self):
|
||||
result = FrontendDocumentLinkHandler.expand_db_attributes({})
|
||||
self.assertEqual(result, "<a>")
|
||||
|
||||
def test_extract_references(self):
|
||||
self.assertEqual(
|
||||
list(
|
||||
RichTextField().extract_references(
|
||||
'<a linktype="document" id="1">Link to a document</a>'
|
||||
)
|
||||
),
|
||||
[(get_document_model(), "1", "", "")],
|
||||
)
|
||||
|
||||
|
||||
class TestEntityFeatureChooserUrls(TestCase):
|
||||
def test_chooser_urls_exist(self):
|
||||
features = FeatureRegistry()
|
||||
document = features.get_editor_plugin("draftail", "document-link")
|
||||
|
||||
self.assertIsNotNone(document.data.get("chooserUrls"))
|
||||
self.assertEqual(
|
||||
document.data["chooserUrls"]["documentChooser"],
|
||||
reverse_lazy("wagtaildocs_chooser:choose"),
|
||||
)
|
||||
109
env/lib/python3.10/site-packages/wagtail/documents/tests/test_search.py
vendored
Normal file
109
env/lib/python3.10/site-packages/wagtail/documents/tests/test_search.py
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
import unittest
|
||||
|
||||
from django.core.files.base import ContentFile
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents import models
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
|
||||
@override_settings(_WAGTAILSEARCH_FORCE_AUTO_UPDATE=["elasticsearch"])
|
||||
class TestIssue613(WagtailTestUtils, TestCase):
|
||||
def get_elasticsearch_backend(self):
|
||||
from django.conf import settings
|
||||
|
||||
from wagtail.search.backends import get_search_backend
|
||||
|
||||
if "elasticsearch" not in settings.WAGTAILSEARCH_BACKENDS:
|
||||
raise unittest.SkipTest("No elasticsearch backend active")
|
||||
|
||||
return get_search_backend("elasticsearch")
|
||||
|
||||
def setUp(self):
|
||||
self.search_backend = self.get_elasticsearch_backend()
|
||||
self.login()
|
||||
|
||||
def add_document(self, **params):
|
||||
# Build a fake file
|
||||
fake_file = ContentFile(b"A boring example document")
|
||||
fake_file.name = "test.txt"
|
||||
|
||||
# Submit
|
||||
post_data = {
|
||||
"title": "Test document",
|
||||
"file": fake_file,
|
||||
}
|
||||
post_data.update(params)
|
||||
response = self.client.post(reverse("wagtaildocs:add"), post_data)
|
||||
|
||||
# User should be redirected back to the index
|
||||
self.assertRedirects(response, reverse("wagtaildocs:index"))
|
||||
|
||||
# Document should be created
|
||||
doc = models.Document.objects.filter(title=post_data["title"])
|
||||
self.assertTrue(doc.exists())
|
||||
return doc.first()
|
||||
|
||||
def edit_document(self, **params):
|
||||
# Build a fake file
|
||||
fake_file = ContentFile(b"A boring example document")
|
||||
fake_file.name = "test.txt"
|
||||
|
||||
# Create a document without tags to edit
|
||||
document = models.Document.objects.create(title="Test document", file=fake_file)
|
||||
|
||||
# Build another fake file
|
||||
another_fake_file = ContentFile(b"A boring example document")
|
||||
another_fake_file.name = "test.txt"
|
||||
|
||||
# Submit
|
||||
post_data = {
|
||||
"title": "Test document changed!",
|
||||
"file": another_fake_file,
|
||||
}
|
||||
post_data.update(params)
|
||||
response = self.client.post(
|
||||
reverse("wagtaildocs:edit", args=(document.id,)), post_data
|
||||
)
|
||||
|
||||
# User should be redirected back to the index
|
||||
self.assertRedirects(response, reverse("wagtaildocs:index"))
|
||||
|
||||
# Document should be changed
|
||||
doc = models.Document.objects.filter(title=post_data["title"])
|
||||
self.assertTrue(doc.exists())
|
||||
return doc.first()
|
||||
|
||||
def test_issue_613_on_add(self):
|
||||
# Reset the search index
|
||||
self.search_backend.reset_index()
|
||||
self.search_backend.add_type(models.Document)
|
||||
|
||||
# Add a document with some tags
|
||||
document = self.add_document(tags="hello")
|
||||
self.search_backend.refresh_index()
|
||||
|
||||
# Search for it by tag
|
||||
results = self.search_backend.search("hello", models.Document)
|
||||
|
||||
# Check
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0].id, document.id)
|
||||
|
||||
def test_issue_613_on_edit(self):
|
||||
# Reset the search index
|
||||
self.search_backend.reset_index()
|
||||
self.search_backend.add_type(models.Document)
|
||||
|
||||
# Add a document with some tags
|
||||
document = self.edit_document(tags="hello")
|
||||
self.search_backend.refresh_index()
|
||||
|
||||
# Search for it by tag
|
||||
results = self.search_backend.search("hello", models.Document)
|
||||
|
||||
# Check
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0].id, document.id)
|
||||
75
env/lib/python3.10/site-packages/wagtail/documents/tests/test_serializers.py
vendored
Normal file
75
env/lib/python3.10/site-packages/wagtail/documents/tests/test_serializers.py
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents import models
|
||||
|
||||
|
||||
class TestCorrectDownloadUrlSerialization(TestCase):
|
||||
|
||||
"""Test asserts that in case of both `redirect` and `direct`
|
||||
WAGTAILDOCS_SERVE_METHOD settings `download_url` field
|
||||
is correctly serialized by DocumentDownloadUrlField."""
|
||||
|
||||
def setUp(self):
|
||||
self.document = models.Document(title="Test document", file_hash="123456")
|
||||
self.document.file.save(
|
||||
"serialization.doc",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
# delete the FieldFile directly because the TestCase does not commit
|
||||
# transactions to trigger transaction.on_commit() in the signal handler
|
||||
self.document.file.delete()
|
||||
|
||||
def get_response(self, document_id, **params):
|
||||
return self.client.get(
|
||||
reverse("wagtailapi_v2:documents:detail", args=(document_id,)), params
|
||||
)
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_SERVE_METHOD="redirect",
|
||||
STORAGES={
|
||||
**settings.STORAGES,
|
||||
"default": {
|
||||
"BACKEND": "wagtail.test.dummy_external_storage.DummyExternalStorage"
|
||||
},
|
||||
},
|
||||
WAGTAILAPI_BASE_URL="http://example.com/",
|
||||
)
|
||||
def test_serializer_wagtaildocs_serve_redirect(self):
|
||||
response = self.get_response(self.document.id)
|
||||
data = response.json()
|
||||
self.assertIn("meta", data)
|
||||
meta = data["meta"]
|
||||
self.assertIn("download_url", meta)
|
||||
download_url = meta["download_url"]
|
||||
expected_url = (
|
||||
f"http://example.com/documents/{self.document.pk}/serialization.doc"
|
||||
)
|
||||
self.assertEqual(download_url, expected_url)
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_SERVE_METHOD="direct",
|
||||
STORAGES={
|
||||
**settings.STORAGES,
|
||||
"default": {
|
||||
"BACKEND": "wagtail.test.dummy_external_storage.DummyExternalStorage"
|
||||
},
|
||||
},
|
||||
MEDIA_URL="http://remotestorage.com/media/",
|
||||
WAGTAILAPI_BASE_URL="http://example.com/",
|
||||
)
|
||||
def test_serializer_wagtaildocs_serve_direct(self):
|
||||
response = self.get_response(self.document.id)
|
||||
data = response.json()
|
||||
self.assertIn("meta", data)
|
||||
meta = data["meta"]
|
||||
self.assertIn("download_url", meta)
|
||||
download_url = meta["download_url"]
|
||||
self.assertEqual(
|
||||
download_url,
|
||||
"http://remotestorage.com/media/documents/serialization.doc",
|
||||
)
|
||||
132
env/lib/python3.10/site-packages/wagtail/documents/tests/test_site_summary.py
vendored
Normal file
132
env/lib/python3.10/site-packages/wagtail/documents/tests/test_site_summary.py
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents import get_document_model
|
||||
from wagtail.documents.wagtail_hooks import DocumentsSummaryItem
|
||||
from wagtail.models import Collection, GroupCollectionPermission, Site
|
||||
from wagtail.test.utils import WagtailTestUtils
|
||||
|
||||
|
||||
class TestDocumentsSummary(WagtailTestUtils, TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
Document = get_document_model()
|
||||
|
||||
# Permissions
|
||||
doc_content_type = ContentType.objects.get_for_model(Document)
|
||||
add_doc_permission = Permission.objects.get(
|
||||
content_type=doc_content_type, codename="add_document"
|
||||
)
|
||||
change_doc_permission = Permission.objects.get(
|
||||
content_type=doc_content_type, codename="change_document"
|
||||
)
|
||||
choose_doc_permission = Permission.objects.get(
|
||||
content_type=doc_content_type, codename="choose_document"
|
||||
)
|
||||
|
||||
# Collections
|
||||
self.root_collection = Collection.get_first_root_node()
|
||||
self.reports_collection = self.root_collection.add_child(name="Birds")
|
||||
|
||||
# Groups
|
||||
doc_changers_group = Group.objects.create(name="Document changers")
|
||||
GroupCollectionPermission.objects.create(
|
||||
group=doc_changers_group,
|
||||
collection=self.root_collection,
|
||||
permission=change_doc_permission,
|
||||
)
|
||||
|
||||
report_adders_group = Group.objects.create(name="Bird adders")
|
||||
GroupCollectionPermission.objects.create(
|
||||
group=report_adders_group,
|
||||
collection=self.reports_collection,
|
||||
permission=add_doc_permission,
|
||||
)
|
||||
|
||||
report_choosers_group = Group.objects.create(name="Bird choosers")
|
||||
GroupCollectionPermission.objects.create(
|
||||
group=report_choosers_group,
|
||||
collection=self.reports_collection,
|
||||
permission=choose_doc_permission,
|
||||
)
|
||||
|
||||
# Users
|
||||
self.superuser = self.create_superuser(
|
||||
"superuser", "superuser@example.com", "password"
|
||||
)
|
||||
|
||||
# a user with add_doc permission on reports via the report_adders group
|
||||
self.report_adder = self.create_user(
|
||||
"reportadder", "reportadder@example.com", "password"
|
||||
)
|
||||
self.report_adder.groups.add(report_adders_group)
|
||||
|
||||
# a user with choose_doc permission on reports via the report_choosers group
|
||||
self.report_chooser = self.create_user(
|
||||
"reportchooser", "reportchooser@example.com", "password"
|
||||
)
|
||||
self.report_chooser.groups.add(report_choosers_group)
|
||||
|
||||
# Documents
|
||||
|
||||
# an doc in the root owned by 'reportadder'
|
||||
self.changer_doc = Document.objects.create(
|
||||
title="reportadder's doc",
|
||||
collection=self.root_collection,
|
||||
uploaded_by_user=self.report_adder,
|
||||
)
|
||||
|
||||
# an doc in reports owned by 'reportadder'
|
||||
self.changer_report = Document.objects.create(
|
||||
title="reportadder's report",
|
||||
collection=self.reports_collection,
|
||||
uploaded_by_user=self.report_adder,
|
||||
)
|
||||
|
||||
# an doc in reports owned by 'reportadder'
|
||||
self.adder_report = Document.objects.create(
|
||||
title="reportadder's report",
|
||||
collection=self.reports_collection,
|
||||
uploaded_by_user=self.report_adder,
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
self.login(self.superuser)
|
||||
|
||||
def get_request(self):
|
||||
return self.client.get(reverse("wagtailadmin_home")).wsgi_request
|
||||
|
||||
def assertSummaryContains(self, content):
|
||||
summary = DocumentsSummaryItem(self.get_request()).render_html()
|
||||
self.assertIn(content, summary)
|
||||
|
||||
def test_site_name_is_shown(self):
|
||||
self.assertEqual(Site.objects.count(), 1)
|
||||
site = Site.objects.first()
|
||||
self.assertSummaryContains(site.site_name)
|
||||
|
||||
def test_user_with_permissions_is_shown_panel(self):
|
||||
self.assertTrue(DocumentsSummaryItem(self.get_request()).is_shown())
|
||||
|
||||
def test_user_with_no_permissions_is_not_shown_panel(self):
|
||||
self.superuser.is_superuser = False
|
||||
self.superuser.user_permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type__app_label="wagtailadmin", codename="access_admin"
|
||||
)
|
||||
)
|
||||
self.superuser.save()
|
||||
self.assertFalse(DocumentsSummaryItem(self.get_request()).is_shown())
|
||||
|
||||
def test_user_sees_proper_doc_count(self):
|
||||
cases = (
|
||||
(self.superuser, "<span>3</span> Documents"),
|
||||
(self.report_adder, "<span>2</span> Documents"),
|
||||
(self.report_chooser, "<span>2</span> Documents"),
|
||||
)
|
||||
for user, content in cases:
|
||||
with self.subTest(user=user):
|
||||
self.login(user)
|
||||
self.assertSummaryContains(content)
|
||||
414
env/lib/python3.10/site-packages/wagtail/documents/tests/test_views.py
vendored
Normal file
414
env/lib/python3.10/site-packages/wagtail/documents/tests/test_views.py
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
import os.path
|
||||
import unittest
|
||||
import urllib
|
||||
from unittest import mock
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from wagtail.documents import models
|
||||
|
||||
|
||||
@override_settings(WAGTAILDOCS_SERVE_METHOD=None)
|
||||
class TestServeView(TestCase):
|
||||
def setUp(self):
|
||||
self.document = models.Document(title="Test document", file_hash="123456")
|
||||
self.document.file.save(
|
||||
"serve_view.doc", ContentFile(b"A boring example document")
|
||||
)
|
||||
self.pdf_document = models.Document(title="Test document", file_hash="123456")
|
||||
self.pdf_document.file.save(
|
||||
"serve_view.pdf", ContentFile(b"A boring example document")
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
if hasattr(self, "response"):
|
||||
# Make sure the response is fully read before deleting the document so
|
||||
# that the file is closed by the view.
|
||||
# This is required on Windows as the below line that deletes the file
|
||||
# will crash if the file is still open.
|
||||
b"".join(self.response.streaming_content)
|
||||
|
||||
# delete the FieldFile directly because the TestCase does not commit
|
||||
# transactions to trigger transaction.on_commit() in the signal handler
|
||||
self.document.file.delete()
|
||||
self.pdf_document.file.delete()
|
||||
|
||||
def get(self, document=None):
|
||||
document = document or self.document
|
||||
self.response = self.client.get(
|
||||
reverse("wagtaildocs_serve", args=(document.id, document.filename))
|
||||
)
|
||||
return self.response
|
||||
|
||||
def test_response_code(self):
|
||||
self.assertEqual(self.get().status_code, 200)
|
||||
|
||||
def test_content_disposition_header(self):
|
||||
self.assertEqual(
|
||||
self.get(self.document)["Content-Disposition"],
|
||||
f'attachment; filename="{self.document.filename}"',
|
||||
)
|
||||
|
||||
def test_inline_content_disposition_header(self):
|
||||
self.assertEqual(
|
||||
self.get(self.pdf_document)["Content-Disposition"],
|
||||
f'inline; filename="{self.pdf_document.filename}"',
|
||||
)
|
||||
|
||||
@mock.patch("wagtail.documents.views.serve.hooks")
|
||||
@mock.patch("wagtail.documents.views.serve.get_object_or_404")
|
||||
def test_non_local_filesystem_content_disposition_header(
|
||||
self, mock_get_object_or_404, mock_hooks
|
||||
):
|
||||
"""
|
||||
Tests the 'Content-Disposition' header in a response when using a
|
||||
storage backend that doesn't expose filesystem paths.
|
||||
"""
|
||||
# Create a mock document with no local file to hit the correct code path
|
||||
mock_doc = mock.Mock()
|
||||
mock_doc.filename = self.document.filename
|
||||
mock_doc.content_type = self.document.content_type
|
||||
mock_doc.content_disposition = self.document.content_disposition
|
||||
mock_doc.file = ContentFile(b"file-like object" * 10)
|
||||
mock_doc.file.path = None
|
||||
mock_doc.file.url = None
|
||||
mock_get_object_or_404.return_value = mock_doc
|
||||
|
||||
# Bypass 'before_serve_document' hooks
|
||||
mock_hooks.get_hooks.return_value = []
|
||||
|
||||
response = self.get()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
self.assertEqual(
|
||||
response["Content-Disposition"],
|
||||
"attachment; filename={0}; filename*=UTF-8''{0}".format(
|
||||
urllib.parse.quote(self.document.filename)
|
||||
),
|
||||
)
|
||||
|
||||
@mock.patch("wagtail.documents.views.serve.hooks")
|
||||
@mock.patch("wagtail.documents.views.serve.get_object_or_404")
|
||||
def test_non_local_filesystem_inline_content_disposition_header(
|
||||
self, mock_get_object_or_404, mock_hooks
|
||||
):
|
||||
"""
|
||||
Tests the 'Content-Disposition' header in a response when using a
|
||||
storage backend that doesn't expose filesystem paths.
|
||||
"""
|
||||
# Create a mock document with no local file to hit the correct code path
|
||||
mock_doc = mock.Mock()
|
||||
mock_doc.filename = self.pdf_document.filename
|
||||
mock_doc.content_type = self.pdf_document.content_type
|
||||
mock_doc.content_disposition = self.pdf_document.content_disposition
|
||||
mock_doc.file = ContentFile(b"file-like object" * 10)
|
||||
mock_doc.file.path = None
|
||||
mock_doc.file.url = None
|
||||
mock_get_object_or_404.return_value = mock_doc
|
||||
|
||||
# Bypass 'before_serve_document' hooks
|
||||
mock_hooks.get_hooks.return_value = []
|
||||
|
||||
response = self.get(self.pdf_document)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
self.assertEqual(response["Content-Disposition"], "inline")
|
||||
|
||||
def test_content_length_header(self):
|
||||
self.assertEqual(self.get()["Content-Length"], "25")
|
||||
|
||||
def test_content_type_header(self):
|
||||
self.assertEqual(self.get()["Content-Type"], "application/msword")
|
||||
|
||||
def test_is_streaming_response(self):
|
||||
self.assertTrue(self.get().streaming)
|
||||
|
||||
def test_content(self):
|
||||
self.assertEqual(
|
||||
b"".join(self.get().streaming_content), b"A boring example document"
|
||||
)
|
||||
|
||||
def test_document_served_fired(self):
|
||||
mock_handler = mock.MagicMock()
|
||||
models.document_served.connect(mock_handler)
|
||||
|
||||
try:
|
||||
self.get()
|
||||
|
||||
self.assertEqual(mock_handler.call_count, 1)
|
||||
self.assertEqual(mock_handler.mock_calls[0][2]["sender"], models.Document)
|
||||
self.assertEqual(mock_handler.mock_calls[0][2]["instance"], self.document)
|
||||
finally:
|
||||
models.document_served.disconnect(mock_handler)
|
||||
|
||||
def test_with_nonexistent_document(self):
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"wagtaildocs_serve",
|
||||
args=(
|
||||
1000,
|
||||
"blahblahblah",
|
||||
),
|
||||
)
|
||||
)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_with_incorrect_filename(self):
|
||||
response = self.client.get(
|
||||
reverse("wagtaildocs_serve", args=(self.document.id, "incorrectfilename"))
|
||||
)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_has_etag_header(self):
|
||||
self.assertEqual(self.get()["ETag"], '"123456"')
|
||||
|
||||
def clear_sendfile_cache(self):
|
||||
from wagtail.utils.sendfile import _get_sendfile
|
||||
|
||||
_get_sendfile.clear()
|
||||
|
||||
|
||||
@override_settings(WAGTAILDOCS_SERVE_METHOD="redirect")
|
||||
class TestServeViewWithRedirect(TestCase):
|
||||
def setUp(self):
|
||||
self.document = models.Document(title="Test document")
|
||||
self.document.file.save(
|
||||
"serve_view_with_redirect.doc",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
self.serve_view_url = reverse(
|
||||
"wagtaildocs_serve", args=(self.document.id, self.document.filename)
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
self.document.delete()
|
||||
|
||||
def get(self):
|
||||
return self.client.get(
|
||||
reverse(
|
||||
"wagtaildocs_serve", args=(self.document.id, self.document.filename)
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_url_should_point_to_serve_view(self):
|
||||
self.assertEqual(self.document.url, self.serve_view_url)
|
||||
|
||||
def test_redirect(self):
|
||||
response = self.get()
|
||||
self.assertRedirects(
|
||||
response, self.document.file.url, fetch_redirect_response=False
|
||||
)
|
||||
|
||||
|
||||
@override_settings(WAGTAILDOCS_SERVE_METHOD="direct")
|
||||
class TestDirectDocumentUrls(TestCase):
|
||||
def setUp(self):
|
||||
self.document = models.Document(title="Test document")
|
||||
self.document.file.save(
|
||||
"direct_document_urls.doc",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
self.document.delete()
|
||||
|
||||
def get(self):
|
||||
return self.client.get(
|
||||
reverse(
|
||||
"wagtaildocs_serve", args=(self.document.id, self.document.filename)
|
||||
)
|
||||
)
|
||||
|
||||
def test_url_should_point_directly_to_file_storage_url(self):
|
||||
self.assertEqual(self.document.url, self.document.file.url)
|
||||
|
||||
def test_redirect(self):
|
||||
# The serve view will not normally be linked to in 'direct' mode, but we should ensure it
|
||||
# still works by redirecting
|
||||
response = self.get()
|
||||
self.assertRedirects(
|
||||
response, self.document.file.url, fetch_redirect_response=False
|
||||
)
|
||||
|
||||
|
||||
@override_settings(
|
||||
WAGTAILDOCS_SERVE_METHOD=None,
|
||||
STORAGES={
|
||||
**settings.STORAGES,
|
||||
"default": {
|
||||
"BACKEND": "wagtail.test.dummy_external_storage.DummyExternalStorage"
|
||||
},
|
||||
},
|
||||
)
|
||||
class TestServeWithExternalStorage(TestCase):
|
||||
"""
|
||||
Test the behaviour of the default serve method when used with a remote storage backend
|
||||
(i.e. one that throws NotImplementedError for the path() method).
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.document = models.Document(title="Test document")
|
||||
self.document.file.save(
|
||||
"serve_with_external_storage.doc",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
self.serve_view_url = reverse(
|
||||
"wagtaildocs_serve", args=(self.document.id, self.document.filename)
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
self.document.delete()
|
||||
|
||||
def test_document_url_should_point_to_serve_view(self):
|
||||
self.assertEqual(self.document.url, self.serve_view_url)
|
||||
|
||||
def test_redirect(self):
|
||||
# serve view should redirect to the remote URL
|
||||
response = self.client.get(self.serve_view_url)
|
||||
self.assertRedirects(
|
||||
response, self.document.file.url, fetch_redirect_response=False
|
||||
)
|
||||
|
||||
|
||||
@override_settings(WAGTAILDOCS_SERVE_METHOD=None)
|
||||
class TestServeViewWithSendfile(TestCase):
|
||||
def setUp(self):
|
||||
# Import using a try-catch block to prevent crashes if the
|
||||
# django-sendfile module is not installed
|
||||
try:
|
||||
import sendfile # noqa: F401
|
||||
except ImportError:
|
||||
raise unittest.SkipTest("django-sendfile not installed")
|
||||
|
||||
self.document = models.Document(title="Test document")
|
||||
self.document.file.save(
|
||||
"serve_view_with_sendfile.doc",
|
||||
ContentFile("A boring example document"),
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
# delete the FieldFile directly because the TestCase does not commit
|
||||
# transactions to trigger transaction.on_commit() in the signal handler
|
||||
self.document.file.delete()
|
||||
|
||||
def get(self):
|
||||
return self.client.get(
|
||||
reverse(
|
||||
"wagtaildocs_serve", args=(self.document.id, self.document.filename)
|
||||
)
|
||||
)
|
||||
|
||||
def clear_sendfile_cache(self):
|
||||
from wagtail.utils.sendfile import _get_sendfile
|
||||
|
||||
_get_sendfile.clear()
|
||||
|
||||
@override_settings(SENDFILE_BACKEND="sendfile.backends.xsendfile")
|
||||
def test_sendfile_xsendfile_backend(self):
|
||||
self.clear_sendfile_cache()
|
||||
response = self.get()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response["X-Sendfile"], self.document.file.path)
|
||||
|
||||
@override_settings(
|
||||
SENDFILE_BACKEND="sendfile.backends.mod_wsgi",
|
||||
SENDFILE_ROOT=settings.MEDIA_ROOT,
|
||||
SENDFILE_URL=settings.MEDIA_URL[:-1],
|
||||
)
|
||||
def test_sendfile_mod_wsgi_backend(self):
|
||||
self.clear_sendfile_cache()
|
||||
response = self.get()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
response["Location"],
|
||||
os.path.join(settings.MEDIA_URL, self.document.file.name),
|
||||
)
|
||||
|
||||
@override_settings(
|
||||
SENDFILE_BACKEND="sendfile.backends.nginx",
|
||||
SENDFILE_ROOT=settings.MEDIA_ROOT,
|
||||
SENDFILE_URL=settings.MEDIA_URL[:-1],
|
||||
)
|
||||
def test_sendfile_nginx_backend(self):
|
||||
self.clear_sendfile_cache()
|
||||
response = self.get()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
response["X-Accel-Redirect"],
|
||||
os.path.join(settings.MEDIA_URL, self.document.file.name),
|
||||
)
|
||||
|
||||
|
||||
@override_settings(WAGTAILDOCS_SERVE_METHOD=None)
|
||||
class TestServeWithUnicodeFilename(TestCase):
|
||||
def setUp(self):
|
||||
self.document = models.Document(title="Test document")
|
||||
|
||||
self.filename = "docs\u0627\u0644\u0643\u0627\u062a\u062f\u0631\u0627"
|
||||
"\u064a\u064a\u0629_\u0648\u0627\u0644\u0633\u0648\u0642"
|
||||
try:
|
||||
self.document.file.save(
|
||||
self.filename, ContentFile("A boring example document")
|
||||
)
|
||||
except UnicodeEncodeError:
|
||||
raise unittest.SkipTest("Filesystem doesn't support unicode filenames")
|
||||
|
||||
def tearDown(self):
|
||||
# delete the FieldFile directly because the TestCase does not commit
|
||||
# transactions to trigger transaction.on_commit() in the signal handler
|
||||
self.document.file.delete()
|
||||
|
||||
def test_response_code(self):
|
||||
response = self.client.get(
|
||||
reverse("wagtaildocs_serve", args=(self.document.id, self.filename))
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@mock.patch("wagtail.documents.views.serve.hooks")
|
||||
@mock.patch("wagtail.documents.views.serve.get_object_or_404")
|
||||
def test_non_local_filesystem_unicode_content_disposition_header(
|
||||
self, mock_get_object_or_404, mock_hooks
|
||||
):
|
||||
"""
|
||||
Tests that a unicode 'Content-Disposition' header (for a response using
|
||||
a storage backend that doesn't expose filesystem paths) doesn't cause an
|
||||
error if encoded differently.
|
||||
"""
|
||||
# Create a mock document to hit the correct code path.
|
||||
mock_doc = mock.Mock()
|
||||
mock_doc.filename = "TÈST.doc"
|
||||
mock_doc.file = ContentFile(b"file-like object" * 10)
|
||||
mock_doc.file.path = None
|
||||
mock_doc.file.url = None
|
||||
mock_get_object_or_404.return_value = mock_doc
|
||||
|
||||
# Bypass 'before_serve_document' hooks
|
||||
mock_hooks.get_hooks.return_value = []
|
||||
|
||||
response = self.client.get(
|
||||
reverse("wagtaildocs_serve", args=(self.document.id, mock_doc.filename))
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
try:
|
||||
response["Content-Disposition"].encode("ascii")
|
||||
except UnicodeDecodeError:
|
||||
self.fail(
|
||||
"Content-Disposition with unicode characters failed ascii encoding."
|
||||
)
|
||||
|
||||
try:
|
||||
response["Content-Disposition"].encode("latin-1")
|
||||
except UnicodeDecodeError:
|
||||
self.fail(
|
||||
"Content-Disposition with unicode characters failed latin-1 encoding."
|
||||
)
|
||||
7
env/lib/python3.10/site-packages/wagtail/documents/tests/utils.py
vendored
Normal file
7
env/lib/python3.10/site-packages/wagtail/documents/tests/utils.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
|
||||
def get_test_document_file():
|
||||
fake_file = ContentFile(b"A boring example document")
|
||||
fake_file.name = "test.txt"
|
||||
return fake_file
|
||||
Reference in New Issue
Block a user