Chore: Share the API client fixtures and build test users cheaply

This commit is contained in:
stumpylog
2026-09-20 16:32:34 -07:00
committed by GitHub
parent f0fb74021c
commit 0973ead3b8
44 changed files with 442 additions and 477 deletions
+42
View File
@@ -15,7 +15,9 @@ if TYPE_CHECKING:
from collections.abc import Generator
from pathlib import Path
from django.contrib.auth.models import User
from pytest_django.fixtures import Settings
from rest_framework.test import APIClient
from paperless_testing.dirs import PaperlessDirs
@@ -82,3 +84,43 @@ def paperless_dirs(
reset_backend()
yield dirs
reset_backend()
@pytest.fixture
def rest_api_client() -> APIClient:
"""The basic DRF APIClient, unauthenticated."""
from rest_framework.test import APIClient
return APIClient()
@pytest.fixture
def regular_user(db: None) -> User:
"""Unprivileged user for permission boundary tests."""
from paperless_testing.factories import UserFactory
return UserFactory(username="regular")
@pytest.fixture
def admin_client(rest_api_client: APIClient, admin_user: User) -> APIClient:
"""Admin client pre-authenticated and sending the v10 Accept header."""
rest_api_client.force_authenticate(user=admin_user)
rest_api_client.credentials(HTTP_ACCEPT="application/json; version=10")
return rest_api_client
@pytest.fixture
def v9_client(rest_api_client: APIClient, admin_user: User) -> APIClient:
"""Admin client pre-authenticated and sending the v9 Accept header."""
rest_api_client.force_authenticate(user=admin_user)
rest_api_client.credentials(HTTP_ACCEPT="application/json; version=9")
return rest_api_client
@pytest.fixture
def user_client(rest_api_client: APIClient, regular_user: User) -> APIClient:
"""Regular-user client pre-authenticated and sending the v10 Accept header."""
rest_api_client.force_authenticate(user=regular_user)
rest_api_client.credentials(HTTP_ACCEPT="application/json; version=10")
return rest_api_client
-42
View File
@@ -5,14 +5,10 @@ from typing import TYPE_CHECKING
import filelock
import pytest
from django.contrib.auth import get_user_model
from pytest_django.fixtures import Settings
from rest_framework.test import APIClient
from paperless_testing.factories import DocumentFactory
UserModelT = get_user_model()
if TYPE_CHECKING:
from documents.models import Document
from paperless_testing.dirs import PaperlessDirs
@@ -76,44 +72,6 @@ def _search_index(
reset_backend()
@pytest.fixture
def rest_api_client():
"""
The basic DRF ApiClient
"""
yield APIClient()
@pytest.fixture()
def regular_user(django_user_model: type[UserModelT]) -> UserModelT:
"""Unprivileged authenticated user for permission boundary tests."""
return django_user_model.objects.create_user(username="regular", password="regular")
@pytest.fixture()
def admin_client(rest_api_client: APIClient, admin_user: UserModelT) -> APIClient:
"""Admin client pre-authenticated and sending the v10 Accept header."""
rest_api_client.force_authenticate(user=admin_user)
rest_api_client.credentials(HTTP_ACCEPT="application/json; version=10")
return rest_api_client
@pytest.fixture()
def v9_client(rest_api_client: APIClient, admin_user: UserModelT) -> APIClient:
"""Admin client pre-authenticated and sending the v9 Accept header."""
rest_api_client.force_authenticate(user=admin_user)
rest_api_client.credentials(HTTP_ACCEPT="application/json; version=9")
return rest_api_client
@pytest.fixture()
def user_client(rest_api_client: APIClient, regular_user: UserModelT) -> APIClient:
"""Regular-user client pre-authenticated and sending the v10 Accept header."""
rest_api_client.force_authenticate(user=regular_user)
rest_api_client.credentials(HTTP_ACCEPT="application/json; version=10")
return rest_api_client
@pytest.fixture
def indexed_document(_search_index: None) -> "Document":
"""One searchable document, for tests about what the search endpoint
@@ -14,7 +14,6 @@ from typing import TYPE_CHECKING
import pytest
import time_machine
from django.contrib.auth.models import User
from documents.models import CustomField
from documents.models import CustomFieldInstance
@@ -23,6 +22,7 @@ from documents.models import Note
from documents.models import StoragePath
from documents.search._query import parse_user_query
from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import UserFactory
if TYPE_CHECKING:
from collections.abc import Callable
@@ -148,7 +148,7 @@ class TestJsonSubpaths:
THEN:
- Only the document with alice's note matches
"""
alice = User.objects.create_user(username="alice")
alice = UserFactory(username="alice")
doc_with_note = DocumentFactory(
title="Has note",
content="x",
+4 -5
View File
@@ -3,7 +3,6 @@ from pathlib import Path
import pytest
from django.contrib.auth.models import Group
from django.contrib.auth.models import User
from django.db import connection
from django.test.utils import CaptureQueriesContext
from guardian.shortcuts import assign_perm
@@ -763,8 +762,8 @@ class TestSearchIds:
def test_respects_permission_filter(self, backend: TantivyBackend) -> None:
"""search_ids must respect user permission filtering."""
owner = User.objects.create_user("ids_owner")
other = User.objects.create_user("ids_other")
owner = UserFactory(username="ids_owner")
other = UserFactory(username="ids_other")
doc = Document.objects.create(
title="private doc",
content="secret keyword",
@@ -1071,7 +1070,7 @@ class TestFieldHandling:
def test_notes_include_user_information(self, backend: TantivyBackend) -> None:
"""Notes must be indexed with user information when available for structured queries."""
user = User.objects.create_user("notewriter")
user = UserFactory(username="notewriter")
doc = Document.objects.create(
title="Doc with notes",
content="test",
@@ -1173,7 +1172,7 @@ class TestHighlightHits:
notes.note: prefix so the query targets notes content directly, but
the snippet is generated from notes_text which stores the same text.
"""
user = User.objects.create_user("hl_noteuser")
user = UserFactory(username="hl_noteuser")
doc = Document.objects.create(
title="Doc with matching note",
content="unrelated content",
@@ -17,12 +17,12 @@ from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from django.contrib.auth.models import User
from documents.models import CustomField
from documents.models import CustomFieldInstance
from documents.models import Note
from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import UserFactory
if TYPE_CHECKING:
from collections.abc import Callable
@@ -53,7 +53,7 @@ class TestBareJsonFieldPrefixes:
decoy's content match does not resurface through a demoted
text search
"""
alice = User.objects.create_user(username="alice")
alice = UserFactory(username="alice")
with_note = DocumentFactory(title="Has note", content="x")
Note.objects.create(document=with_note, user=alice, note="crocodile")
backend.add_or_update(with_note)
@@ -116,7 +116,7 @@ class TestBareJsonFieldPrefixes:
document; the default-subpath resolution for the bare
prefix does not interfere with explicit subpath addressing
"""
bob = User.objects.create_user(username="bob")
bob = UserFactory(username="bob")
doc = DocumentFactory(title="Bob note", content="x")
Note.objects.create(document=doc, user=bob, note="remark")
backend.add_or_update(doc)
@@ -20,7 +20,6 @@ from typing import TYPE_CHECKING
import pytest
import tantivy
from django.contrib.auth.models import User
from whoosh_compat import FieldKind
from documents.models import CustomField
@@ -28,6 +27,7 @@ from documents.models import CustomFieldInstance
from documents.models import Document
from documents.models import Note
from documents.search._fields import PUBLIC_FIELDS
from paperless_testing.factories import UserFactory
if TYPE_CHECKING:
from documents.search._backend import TantivyBackend
@@ -49,7 +49,7 @@ class TestJsonSubpathsAreWrittenAtIndexTime:
- Every subpath PUBLIC_FIELDS declares for notes/custom_fields
is present as a key in the document's stored JSON payload
"""
user = User.objects.create_user(username="completeness-user")
user = UserFactory(username="completeness-user")
field = CustomField.objects.create(
name="Completeness Field",
data_type=CustomField.FieldDataType.STRING,
@@ -25,6 +25,7 @@ from documents.models import Document
from documents.models import DocumentType
from documents.models import StoragePath
from documents.models import Tag
from paperless_testing.factories import UserFactory
if TYPE_CHECKING:
from documents.search._backend import TantivyBackend
@@ -34,22 +35,22 @@ pytestmark = [pytest.mark.search, pytest.mark.django_db]
@pytest.fixture
def owner() -> User:
return User.objects.create_user(username="owner")
return UserFactory(username="owner")
@pytest.fixture
def stranger() -> User:
return User.objects.create_user(username="stranger")
return UserFactory(username="stranger")
@pytest.fixture
def viewer() -> User:
return User.objects.create_user(username="viewer")
return UserFactory(username="viewer")
@pytest.fixture
def group_member() -> User:
user = User.objects.create_user(username="group_member")
user = UserFactory(username="group_member")
user.groups.add(Group.objects.create(name="accounting"))
return user
+3 -3
View File
@@ -3,7 +3,6 @@ from io import BytesIO
from pathlib import Path
from unittest.mock import patch
from django.contrib.auth.models import User
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import override_settings
from PIL import Image
@@ -15,6 +14,7 @@ from documents.tests.utils import read_streaming_response
from paperless.models import ApplicationConfiguration
from paperless.models import ColorConvertChoices
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestApiAppConfig(DirectoriesMixin, APITestCase):
@@ -23,7 +23,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
user = User.objects.create_superuser(username="temp_admin")
user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=user)
def test_api_get_config(self) -> None:
@@ -267,7 +267,7 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
THEN:
- old app_logo file is deleted
"""
admin = User.objects.create_superuser(username="admin")
admin = UserFactory(username="admin", superuser=True)
self.client.force_login(user=admin)
response = self.client.get("/logo/")
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
@@ -5,7 +5,6 @@ import shutil
import zipfile
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import override_settings
from django.utils import timezone
from rest_framework import status
@@ -17,6 +16,7 @@ from documents.models import DocumentType
from documents.tests.utils import SampleDirMixin
from documents.tests.utils import read_streaming_response
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestBulkDownload(DirectoriesMixin, SampleDirMixin, APITestCase):
@@ -25,7 +25,7 @@ class TestBulkDownload(DirectoriesMixin, SampleDirMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
self.doc1 = Document.objects.create(title="unrelated", checksum="A")
@@ -326,7 +326,7 @@ class TestBulkDownload(DirectoriesMixin, SampleDirMixin, APITestCase):
)
def test_download_insufficient_permissions(self) -> None:
user = User.objects.create_user(username="temp_user")
user = UserFactory(username="temp_user")
user.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
+8 -7
View File
@@ -16,13 +16,14 @@ from documents.models import DocumentType
from documents.models import StoragePath
from documents.models import Tag
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestBulkEditAPI(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
user = User.objects.create_superuser(username="temp_admin")
user = UserFactory(username="temp_admin", superuser=True)
self.user = user
self.client.force_authenticate(user=user)
@@ -284,9 +285,9 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
m,
) -> None:
self.setup_mock(m, "modify_custom_fields")
user = User.objects.create_user(username="doc-owner")
user = UserFactory(username="doc-owner")
user.user_permissions.add(Permission.objects.get(codename="change_document"))
other_user = User.objects.create_user(username="other-user")
other_user = UserFactory(username="other-user")
source_doc = Document.objects.create(
checksum="source",
title="Source",
@@ -787,7 +788,7 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
@mock.patch("documents.serialisers.bulk_edit.set_storage_path")
def test_api_bulk_edit_with_all_true_resolves_owned_duplicates(self, m) -> None:
self.setup_mock(m, "set_storage_path")
user = User.objects.create_user(username="duplicate-owner")
user = UserFactory(username="duplicate-owner")
user.user_permissions.add(
Permission.objects.get(codename="change_document"),
)
@@ -1919,7 +1920,7 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
@mock.patch("documents.views.bulk_edit.merge")
def test_merge_and_delete_requires_change_permission(self, m) -> None:
self.setup_mock(m, "merge")
user = User.objects.create_user(username="no-change")
user = UserFactory(username="no-change")
user.user_permissions.add(
Permission.objects.get(codename="add_document"),
Permission.objects.get(codename="delete_document"),
@@ -2345,7 +2346,7 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
@mock.patch("documents.views.bulk_edit.edit_pdf")
def test_edit_pdf_update_requires_change_permission(self, m) -> None:
self.setup_mock(m, "edit_pdf")
user = User.objects.create_user(username="no-change")
user = UserFactory(username="no-change")
self.client.force_authenticate(user=user)
response = self.client.post(
@@ -2372,7 +2373,7 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
) -> None:
self.setup_mock(edit_pdf_mock, "edit_pdf")
self.setup_mock(remove_password_mock, "remove_password")
user = User.objects.create_user(username="no-delete")
user = UserFactory(username="no-delete")
user.user_permissions.add(
Permission.objects.get(codename="add_document"),
Permission.objects.get(codename="change_document"),
+3 -1
View File
@@ -10,6 +10,8 @@ from rest_framework import status
from rest_framework.test import APIClient
from rest_framework.test import APITestCase
from paperless_testing.factories import UserFactory
if TYPE_CHECKING:
from pytest_mock import MockerFixture
@@ -17,7 +19,7 @@ if TYPE_CHECKING:
class TestChatStreamingViewInputValidation(APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
def _mock_ai_enabled(self) -> mock.MagicMock:
@@ -4,7 +4,6 @@ from unittest import mock
from unittest.mock import ANY
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import override_settings
from guardian.shortcuts import assign_perm
from rest_framework import status
@@ -14,13 +13,14 @@ from documents.models import CustomField
from documents.models import CustomFieldInstance
from documents.models import Document
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
ENDPOINT = "/api/custom_fields/"
def setUp(self) -> None:
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
return super().setUp()
@@ -1174,11 +1174,11 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
def test_documentlink_patch_requires_change_permission_on_target_documents(
self,
) -> None:
source_owner = User.objects.create_user(username="source-owner")
source_owner = UserFactory(username="source-owner")
source_owner.user_permissions.add(
Permission.objects.get(codename="change_document"),
)
other_user = User.objects.create_user(username="other-user")
other_user = UserFactory(username="other-user")
source_doc = Document.objects.create(
title="Source",
@@ -1221,11 +1221,11 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
def test_documentlink_patch_allowed_with_change_permission_on_target_documents(
self,
) -> None:
source_owner = User.objects.create_user(username="source-owner")
source_owner = UserFactory(username="source-owner")
source_owner.user_permissions.add(
Permission.objects.get(codename="change_document"),
)
other_user = User.objects.create_user(username="other-user")
other_user = UserFactory(username="other-user")
source_doc = Document.objects.create(
title="Source",
@@ -1337,7 +1337,7 @@ class TestCustomFieldsAPI(DirectoriesMixin, APITestCase):
self.assertEqual(results[0]["document_count"], 1)
# Test as user without access to the document
non_superuser = User.objects.create_user(username="non_superuser")
non_superuser = UserFactory(username="non_superuser")
non_superuser.user_permissions.add(
*Permission.objects.exclude(codename="view_global_statistics"),
)
@@ -6,7 +6,6 @@ from unittest import mock
from auditlog.models import LogEntry # type: ignore[import-untyped]
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase as DjangoTestCase
@@ -22,6 +21,7 @@ from documents.tests.utils import read_streaming_response
from documents.versioning import annotate_effective_content
from documents.views import DocumentSelectionMixin
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
if TYPE_CHECKING:
from pathlib import Path
@@ -31,7 +31,7 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
def _make_pdf_upload(self, name: str = "version.pdf") -> SimpleUploadedFile:
@@ -89,8 +89,8 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
def test_root_endpoint_returns_403_when_user_lacks_permission(self) -> None:
owner = User.objects.create_user(username="owner")
viewer = User.objects.create_user(username="viewer")
owner = UserFactory(username="owner")
viewer = UserFactory(username="viewer")
viewer.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -283,8 +283,8 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
self.assertEqual(mock_backend.add_or_update.call_args[0][0].id, root.id)
def test_delete_version_returns_403_without_permission(self) -> None:
owner = User.objects.create_user(username="owner")
other = User.objects.create_user(username="other")
owner = UserFactory(username="owner")
other = UserFactory(username="other")
other.user_permissions.add(
Permission.objects.get(codename="delete_document"),
)
@@ -371,8 +371,8 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
self.assertTrue(resp.data["is_root"])
def test_update_version_label_returns_403_without_permission(self) -> None:
owner = User.objects.create_user(username="owner")
other = User.objects.create_user(username="other")
owner = UserFactory(username="owner")
other = UserFactory(username="other")
other.user_permissions.add(
Permission.objects.get(codename="change_document"),
)
@@ -553,8 +553,8 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
def test_metadata_returns_403_when_user_lacks_permission(self) -> None:
owner = User.objects.create_user(username="owner")
other = User.objects.create_user(username="other")
owner = UserFactory(username="owner")
other = UserFactory(username="other")
other.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -653,8 +653,8 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
self.assertEqual(resp.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
def test_update_version_returns_403_without_permission(self) -> None:
owner = User.objects.create_user(username="owner")
other = User.objects.create_user(username="other")
owner = UserFactory(username="owner")
other = UserFactory(username="other")
root = Document.objects.create(
title="root",
checksum="root",
@@ -672,7 +672,7 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
def test_update_version_requires_global_change_permission(self) -> None:
user = User.objects.create_user(username="add-only")
user = UserFactory(username="add-only")
user.user_permissions.add(Permission.objects.get(codename="add_document"))
root = Document.objects.create(
title="root",
@@ -978,7 +978,7 @@ class TestVersionAwareFilters(DjangoTestCase):
superseded content -- selecting documents the list view, filtered by
the same term, does not show.
"""
user = User.objects.create_superuser(username="bulk_selection")
user = UserFactory(username="bulk_selection", superuser=True)
selected = DocumentSelectionMixin()._resolve_document_ids(
user=user,
@@ -1005,7 +1005,7 @@ class TestBulkSelectionExcludesVersions(DjangoTestCase):
"Select all matching" reconstructs the document list, which never
contains version documents as rows of their own.
"""
user = User.objects.create_superuser(username="bulk_versions")
user = UserFactory(username="bulk_versions", superuser=True)
root = Document.objects.create(
title="shared-title root",
checksum="bulk-root",
+44 -43
View File
@@ -53,13 +53,14 @@ from documents.tests.utils import read_streaming_response
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import TagFactory
from paperless_testing.factories import UserFactory
class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
cache.clear()
@@ -357,8 +358,8 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
with Path(filename).open("wb") as f:
f.write(content)
user1 = User.objects.create_user(username="test1")
user2 = User.objects.create_user(username="test2")
user1 = UserFactory(username="test1")
user2 = UserFactory(username="test2")
user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
user2.user_permissions.add(*Permission.objects.filter(codename="view_document"))
@@ -760,7 +761,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
- History is returned
"""
# No auditlog permissions
user = User.objects.create_user(username="test")
user = UserFactory(username="test")
user.user_permissions.add(*Permission.objects.filter(codename="view_document"))
self.client.force_authenticate(user=user)
doc = Document.objects.create(
@@ -776,7 +777,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
# superuser
user.is_superuser = True
user.save()
user2 = User.objects.create_user(username="test2")
user2 = UserFactory(username="test2")
doc2 = Document.objects.create(
title="Second title",
checksum="456",
@@ -1073,8 +1074,8 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
self.assertEqual(response.data["duplicate_documents"], [])
def test_has_duplicates_filter_respects_document_permissions(self) -> None:
owner = User.objects.create_user(username="duplicate-owner")
requester = User.objects.create_user(username="duplicate-requester")
owner = UserFactory(username="duplicate-owner")
requester = UserFactory(username="duplicate-requester")
requester.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -1317,8 +1318,8 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Owner filters work correctly but still respect permissions
"""
u1 = User.objects.create_user("user1")
u2 = User.objects.create_user("user2")
u1 = UserFactory(username="user1")
u2 = UserFactory(username="user2")
u1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
u2.user_permissions.add(*Permission.objects.filter(codename="view_document"))
@@ -1424,7 +1425,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
- The document is returned exactly once, not once per permission path
(regression test for https://github.com/paperless-ngx/paperless-ngx/issues/13331)
"""
user = User.objects.create_user("user1")
user = UserFactory(username="user1")
user.user_permissions.add(*Permission.objects.filter(codename="view_document"))
group = Group.objects.create(name="group1")
user.groups.add(group)
@@ -1452,8 +1453,8 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- The document does not appear in their results
"""
owner = User.objects.create_user("owner1")
stranger = User.objects.create_user("stranger1")
owner = UserFactory(username="owner1")
stranger = UserFactory(username="stranger1")
stranger.user_permissions.add(
*Permission.objects.filter(codename="view_document"),
)
@@ -1474,9 +1475,9 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Only the group member sees the document
"""
owner = User.objects.create_user("owner2")
member = User.objects.create_user("member1")
non_member = User.objects.create_user("nonmember1")
owner = UserFactory(username="owner2")
member = UserFactory(username="member1")
non_member = UserFactory(username="nonmember1")
for u in (member, non_member):
u.user_permissions.add(*Permission.objects.filter(codename="view_document"))
@@ -1785,8 +1786,8 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Statistics only include inbox counts for tags accessible by the user
"""
u1 = User.objects.create_user("user1")
u2 = User.objects.create_user("user2")
u1 = UserFactory(username="user1")
u2 = UserFactory(username="user2")
inbox_tag_u1 = Tag.objects.create(name="inbox_u1", is_inbox_tag=True, owner=u1)
Tag.objects.create(name="inbox_u2", is_inbox_tag=True, owner=u2)
doc_u1 = Document.objects.create(
@@ -1816,8 +1817,8 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
self.assertEqual(response.data["documents_inbox"], 0)
def test_statistics_with_statistics_permission(self) -> None:
owner = User.objects.create_user("owner")
stats_user = User.objects.create_user("stats-user")
owner = UserFactory(username="owner")
stats_user = UserFactory(username="stats-user")
stats_user.user_permissions.add(
Permission.objects.get(codename="view_global_statistics"),
)
@@ -1986,7 +1987,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED)
def test_upload_insufficient_permissions(self) -> None:
self.client.force_authenticate(user=User.objects.create_user("testuser2"))
self.client.force_authenticate(user=UserFactory(username="testuser2"))
with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
response = self.client.post(
@@ -2782,9 +2783,9 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
mock_get_date_parser.assert_not_called()
def test_saved_views(self) -> None:
u1 = User.objects.create_user("user1")
u2 = User.objects.create_user("user2")
u3 = User.objects.create_user("user3")
u1 = UserFactory(username="user1")
u2 = UserFactory(username="user2")
u3 = UserFactory(username="user3")
view_perm = Permission.objects.get(codename="view_savedview")
change_perm = Permission.objects.get(codename="change_savedview")
@@ -3064,7 +3065,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
self.assertListEqual(saved_view_settings["sidebar_views_visible_ids"], [v2.id])
def test_saved_view_create_update_patch(self) -> None:
User.objects.create_user("user1")
UserFactory(username="user1")
view = {
"name": "test",
@@ -3127,7 +3128,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
- Display options are updated
- Display fields are validated
"""
User.objects.create_user("user1")
UserFactory(username="user1")
view = {
"name": "test",
@@ -3568,11 +3569,11 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Notes are neither created nor deleted
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.all())
user1.save()
user2 = User.objects.create_user(username="test2")
user2 = UserFactory(username="test2")
user2.save()
doc = Document.objects.create(
@@ -3616,7 +3617,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_notes_require_global_document_permissions(self) -> None:
user = User.objects.create_user(username="note_editor")
user = UserFactory(username="note_editor")
user.user_permissions.add(
*Permission.objects.filter(
codename__in=["view_note", "add_note", "delete_note"],
@@ -3797,11 +3798,11 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
- Unique items are created
- Non-unique items are not allowed
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.filter(codename="add_tag"))
user1.save()
user2 = User.objects.create_user(username="test2")
user2 = UserFactory(username="test2")
user2.user_permissions.add(*Permission.objects.filter(codename="add_tag"))
user2.save()
@@ -3857,11 +3858,11 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
- Unique items are created
- Non-unique items are not allowed on update
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.filter(codename="change_tag"))
user1.save()
user2 = User.objects.create_user(username="test2")
user2 = UserFactory(username="test2")
user2.user_permissions.add(*Permission.objects.filter(codename="change_tag"))
user2.save()
@@ -3993,11 +3994,11 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Links only shown if user has permissions
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.all())
user1.save()
user2 = User.objects.create_user(username="test2")
user2 = UserFactory(username="test2")
user2.save()
doc = Document.objects.create(
@@ -4034,11 +4035,11 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Share link creation is denied until view permission is granted
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.filter(codename="add_sharelink"))
user1.save()
user2 = User.objects.create_user(username="test2")
user2 = UserFactory(username="test2")
user2.save()
doc = Document.objects.create(
@@ -4097,11 +4098,11 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- ASN +1 from user2's doc is returned for user1
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.all())
user1.save()
user2 = User.objects.create_user(username="test2")
user2 = UserFactory(username="test2")
user2.save()
doc1 = Document.objects.create(
@@ -4141,7 +4142,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- ASN 1 is returned
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.all())
user1.save()
@@ -4170,7 +4171,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Explicit error is returned
"""
user1 = User.objects.create_superuser(username="test1")
user1 = UserFactory(username="test1", superuser=True)
self.client.force_authenticate(user1)
@@ -4348,7 +4349,7 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
THEN:
- Error response is returned
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.all())
user1.save()
@@ -4454,7 +4455,7 @@ class TestDocumentApiTagColors(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
@@ -4534,7 +4535,7 @@ class TestDocumentApiCustomFieldsSorting(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
self.doc1 = Document.objects.create(
+4 -4
View File
@@ -3,7 +3,6 @@ import shutil
from unittest import mock
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.core import mail
from django.test import override_settings
from rest_framework import status
@@ -12,6 +11,7 @@ from rest_framework.test import APITestCase
from documents.models import Document
from documents.tests.utils import SampleDirMixin
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
@@ -20,7 +20,7 @@ class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
self.doc1 = Document.objects.create(
@@ -303,7 +303,7 @@ class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
THEN:
- Forbidden response is returned
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
doc_owned = Document.objects.create(
@@ -338,7 +338,7 @@ class TestEmail(DirectoriesMixin, SampleDirMixin, APITestCase):
THEN:
- Request succeeds
"""
user1 = User.objects.create_user(username="test1")
user1 = UserFactory(username="test1")
user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
self.client.force_authenticate(user1)
@@ -4,7 +4,6 @@ from collections.abc import Callable
from datetime import date
from urllib.parse import quote
from django.contrib.auth.models import User
from rest_framework.test import APITestCase
from documents.models import CustomField
@@ -14,6 +13,7 @@ from documents.models import SavedView
from documents.models import SavedViewFilterRule
from documents.serialisers import DocumentSerializer
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class DocumentWrapper:
@@ -35,7 +35,7 @@ class TestCustomFieldsSearch(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
# Create one custom field per type. The fields are called f"{type}_field".
+18 -17
View File
@@ -22,13 +22,14 @@ from documents.models import DocumentType
from documents.models import StoragePath
from documents.models import Tag
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestApiObjects(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
user = User.objects.create_superuser(username="temp_admin")
user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=user)
self.tag1 = Tag.objects.create(name="t1", is_inbox_tag=True)
@@ -153,7 +154,7 @@ class TestApiObjects(DirectoriesMixin, APITestCase):
# A newer document owned by another user must not leak through the
# aggregate for a non-superuser who cannot view it
other = User.objects.create_user(username="other")
other = UserFactory(username="other")
Document.objects.create(
mime_type="application/pdf",
correspondent=self.c1,
@@ -162,7 +163,7 @@ class TestApiObjects(DirectoriesMixin, APITestCase):
owner=other,
)
user = User.objects.create_user(username="regular")
user = UserFactory(username="regular")
user.user_permissions.add(
Permission.objects.get(codename="view_correspondent"),
)
@@ -200,7 +201,7 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
user = User.objects.create_superuser(username="temp_admin")
user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=user)
self.sp1 = StoragePath.objects.create(name="sp1", path="Something/{checksum}")
@@ -455,8 +456,8 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
self.assertEqual(response.data, "folder/Something.pdf")
def test_test_storage_path_requires_document_view_permission(self) -> None:
owner = User.objects.create_user(username="owner")
unprivileged = User.objects.create_user(username="unprivileged")
owner = UserFactory(username="owner")
unprivileged = UserFactory(username="unprivileged")
unprivileged.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -481,8 +482,8 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
self.assertIn("document", response.data)
def test_test_storage_path_allows_shared_document_view_permission(self) -> None:
owner = User.objects.create_user(username="owner")
viewer = User.objects.create_user(username="viewer")
owner = UserFactory(username="owner")
viewer = UserFactory(username="viewer")
document = Document.objects.create(
mime_type="application/pdf",
owner=owner,
@@ -545,7 +546,7 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
def test_test_storage_path_exposes_basic_document_context_but_not_sensitive_owner_data(
self,
) -> None:
owner = User.objects.create_user(
owner = UserFactory(
username="owner",
password="password",
email="owner@example.com",
@@ -614,8 +615,8 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
def test_test_storage_path_includes_related_objects_for_visible_document(
self,
) -> None:
owner = User.objects.create_user(username="owner")
viewer = User.objects.create_user(username="viewer")
owner = UserFactory(username="owner")
viewer = UserFactory(username="viewer")
private_correspondent = Correspondent.objects.create(
name="Private Correspondent",
owner=owner,
@@ -662,7 +663,7 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
self.assertEqual(response.data, "Private Correspondent.pdf")
def test_test_storage_path_superuser_can_view_private_related_objects(self) -> None:
owner = User.objects.create_user(username="owner")
owner = UserFactory(username="owner")
private_correspondent = Correspondent.objects.create(
name="Private Correspondent",
owner=owner,
@@ -693,8 +694,8 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
def test_test_storage_path_includes_doc_type_storage_path_and_tags(
self,
) -> None:
owner = User.objects.create_user(username="owner")
viewer = User.objects.create_user(username="viewer")
owner = UserFactory(username="owner")
viewer = UserFactory(username="viewer")
private_document_type = DocumentType.objects.create(
name="Private Type",
owner=owner,
@@ -756,8 +757,8 @@ class TestApiStoragePaths(DirectoriesMixin, APITestCase):
def test_test_storage_path_includes_custom_fields_for_visible_document(
self,
) -> None:
owner = User.objects.create_user(username="owner")
viewer = User.objects.create_user(username="viewer")
owner = UserFactory(username="owner")
viewer = UserFactory(username="viewer")
document = Document.objects.create(
mime_type="application/pdf",
owner=owner,
@@ -798,7 +799,7 @@ class TestBulkEditObjects(APITestCase):
def setUp(self) -> None:
super().setUp()
self.temp_admin = User.objects.create_superuser(username="temp_admin")
self.temp_admin = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.temp_admin)
self.t1 = Tag.objects.create(name="t1")
+29 -28
View File
@@ -20,6 +20,7 @@ from documents.models import MatchingModel
from documents.models import StoragePath
from documents.models import Tag
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestApiAuth(DirectoriesMixin, APITestCase):
@@ -93,14 +94,14 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
self.assertNotIn("X-Version", response)
def test_api_version_with_auth(self) -> None:
user = User.objects.create_superuser(username="test")
user = UserFactory(username="test", superuser=True)
self.client.force_authenticate(user)
response = self.client.get("/api/documents/")
self.assertIn("X-Api-Version", response)
self.assertIn("X-Version", response)
def test_api_insufficient_permissions(self) -> None:
user = User.objects.create_user(username="test")
user = UserFactory(username="test")
self.client.force_authenticate(user)
Document.objects.create(title="Test")
@@ -137,7 +138,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
)
def test_api_sufficient_permissions(self) -> None:
user = User.objects.create_user(username="test")
user = UserFactory(username="test")
user.user_permissions.add(*Permission.objects.all())
user.is_staff = True
self.client.force_authenticate(user)
@@ -166,8 +167,8 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
)
def test_api_get_object_permissions(self) -> None:
user1 = User.objects.create_user(username="test1")
user2 = User.objects.create_user(username="test2")
user1 = UserFactory(username="test1")
user2 = UserFactory(username="test2")
user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
self.client.force_authenticate(user1)
@@ -205,7 +206,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
THEN:
- Object created with current user as owner
"""
user1 = User.objects.create_superuser(username="user1")
user1 = UserFactory(username="user1", superuser=True)
self.client.force_authenticate(user1)
@@ -234,7 +235,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
THEN:
- Object created with no owner
"""
user1 = User.objects.create_superuser(username="user1")
user1 = UserFactory(username="user1", superuser=True)
self.client.force_authenticate(user1)
@@ -265,7 +266,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
THEN:
- Object permissions are set appropriately
"""
user1 = User.objects.create_superuser(username="user1")
user1 = UserFactory(username="user1", superuser=True)
user2 = User.objects.create(username="user2")
group1 = Group.objects.create(name="group1")
@@ -313,7 +314,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
THEN:
- Object permissions are set appropriately
"""
user1 = User.objects.create_superuser(username="user1")
user1 = UserFactory(username="user1", superuser=True)
user2 = User.objects.create(username="user2")
group1 = Group.objects.create(name="group1")
@@ -363,7 +364,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
mime_type="application/pdf",
content="this is a document",
)
user1 = User.objects.create_superuser(username="user1")
user1 = UserFactory(username="user1", superuser=True)
user2 = User.objects.create(username="user2")
group1 = Group.objects.create(name="group1")
@@ -413,7 +414,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
mime_type="application/pdf",
content="this is a document",
)
user1 = User.objects.create_superuser(username="user1")
user1 = UserFactory(username="user1", superuser=True)
user2 = User.objects.create(username="user2")
group1 = Group.objects.create(name="group1")
doc.owner = user1
@@ -446,8 +447,8 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
self.assertIn("change_document", get_perms(group1, doc))
def test_document_permissions_change_requires_owner(self) -> None:
owner = User.objects.create_user(username="owner")
editor = User.objects.create_user(username="editor")
owner = UserFactory(username="owner")
editor = UserFactory(username="editor")
editor.user_permissions.add(
*Permission.objects.all(),
)
@@ -499,9 +500,9 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_dynamic_permissions_fields(self) -> None:
user1 = User.objects.create_user(username="user1")
user1 = UserFactory(username="user1")
user1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
user2 = User.objects.create_user(username="user2")
user2 = UserFactory(username="user2")
Document.objects.create(title="Test", content="content 1", checksum="1")
doc2 = Document.objects.create(
@@ -574,8 +575,8 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
owned by someone else with no explicit guardian grant -- mirrors
guardian's own ObjectPermissionChecker.has_perm() superuser shortcut.
"""
superuser = User.objects.create_superuser(username="admin")
other_user = User.objects.create_user(username="user2")
superuser = UserFactory(username="admin", superuser=True)
other_user = UserFactory(username="user2")
Document.objects.create(
title="Test",
content="content",
@@ -602,7 +603,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
THEN:
- MFA required error is returned
"""
user1 = User.objects.create_user(username="user1")
user1 = UserFactory(username="user1")
user1.set_password("password")
user1.save()
@@ -626,7 +627,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
THEN:
- MFA code is required
"""
user1 = User.objects.create_user(username="user1")
user1 = UserFactory(username="user1")
user1.set_password("password")
user1.save()
@@ -688,7 +689,7 @@ class TestApiUser(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
def test_get_users(self) -> None:
@@ -858,7 +859,7 @@ class TestApiUser(DirectoriesMixin, APITestCase):
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
regular_user = User.objects.create_user(username="regular_user")
regular_user = UserFactory(username="regular_user")
regular_user.user_permissions.add(
*Permission.objects.all(),
)
@@ -885,9 +886,9 @@ class TestApiUser(DirectoriesMixin, APITestCase):
- Only superusers can change superuser status
"""
user1 = User.objects.create_user(username="user1")
user1 = UserFactory(username="user1")
user1.user_permissions.add(*Permission.objects.all())
user2 = User.objects.create_superuser(username="user2")
user2 = UserFactory(username="user2", superuser=True)
self.client.force_authenticate(user1)
@@ -972,9 +973,9 @@ class TestApiUser(DirectoriesMixin, APITestCase):
- Only superusers can change staff status
"""
user1 = User.objects.create_user(username="user1")
user1 = UserFactory(username="user1")
user1.user_permissions.add(*Permission.objects.all())
user2 = User.objects.create_superuser(username="user2")
user2 = UserFactory(username="user2", superuser=True)
self.client.force_authenticate(user1)
@@ -1027,7 +1028,7 @@ class TestApiGroup(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
def test_get_groups(self) -> None:
@@ -1128,7 +1129,7 @@ class TestBulkEditObjectPermissions(APITestCase):
def setUp(self) -> None:
super().setUp()
self.temp_admin = User.objects.create_superuser(username="temp_admin")
self.temp_admin = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.temp_admin)
self.t1 = Tag.objects.create(name="t1")
@@ -1680,7 +1681,7 @@ class TestFullPermissionsFlag(APITestCase):
def setUp(self) -> None:
super().setUp()
self.admin = User.objects.create_superuser(username="admin")
self.admin = UserFactory(username="admin", superuser=True)
def test_full_perms_flag(self) -> None:
"""
+4 -2
View File
@@ -9,6 +9,7 @@ from rest_framework.authtoken.models import Token
from rest_framework.test import APITestCase
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
# see allauth.socialaccount.providers.openid.provider.OpenIDProvider
@@ -55,10 +56,11 @@ class TestApiProfile(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(
self.user = UserFactory(
username="temp_admin",
first_name="firstname",
last_name="surname",
superuser=True,
)
self.client.force_authenticate(user=self.user)
@@ -401,7 +403,7 @@ class TestApiTOTPViews(APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
def test_get_totp(self) -> None:
+21 -21
View File
@@ -7,7 +7,6 @@ import time_machine
from dateutil.relativedelta import relativedelta
from django.contrib.auth.models import Group
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import override_settings
from django.utils import timezone
from guardian.shortcuts import assign_perm
@@ -31,6 +30,7 @@ from paperless_mail.models import MailAccount
from paperless_mail.models import MailRule
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import UserFactory
pytestmark = pytest.mark.search
@@ -40,7 +40,7 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
super().setUp()
reset_backend()
self.user = User.objects.create_superuser(username="temp_admin")
self.user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=self.user)
def tearDown(self) -> None:
@@ -949,8 +949,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
THEN:
- Terms only within docs user has access to are returned
"""
u1 = User.objects.create_user("user1")
u2 = User.objects.create_user("user2")
u1 = UserFactory(username="user1")
u2 = UserFactory(username="user2")
u1.user_permissions.add(Permission.objects.get(codename="view_document"))
self.client.force_authenticate(user=u1)
@@ -999,8 +999,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
self.assertEqual(response.data, ["applebaum", "apples", "appletini"])
def test_search_autocomplete_group_revocation_is_immediate(self) -> None:
user = User.objects.create_user("group-user")
owner = User.objects.create_user("document-owner")
user = UserFactory(username="group-user")
owner = UserFactory(username="document-owner")
group = Group.objects.create(name="temporary-viewers")
user.user_permissions.add(Permission.objects.get(codename="view_document"))
user.groups.add(group)
@@ -1091,8 +1091,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
self.assertIsNone(response.data["corrected_query"])
def test_search_spelling_suggestion_suppressed_for_private_terms(self) -> None:
owner = User.objects.create_user("owner")
attacker = User.objects.create_user("attacker")
owner = UserFactory(username="owner")
attacker = UserFactory(username="attacker")
attacker.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -1222,8 +1222,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
THEN:
- The request is rejected
"""
owner = User.objects.create_user("owner")
attacker = User.objects.create_user("attacker")
owner = UserFactory(username="owner")
attacker = UserFactory(username="attacker")
attacker.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -1534,9 +1534,9 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
- Only owned docs are returned for regular users
- All docs are returned for superuser
"""
superuser = User.objects.create_superuser("superuser")
u1 = User.objects.create_user("user1")
u2 = User.objects.create_user("user2")
superuser = UserFactory(username="superuser", superuser=True)
u1 = UserFactory(username="user1")
u2 = UserFactory(username="user2")
u1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
u2.user_permissions.add(*Permission.objects.filter(codename="view_document"))
@@ -1588,8 +1588,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
THEN:
- Only docs with granted view permissions are returned
"""
u1 = User.objects.create_user("user1")
u2 = User.objects.create_user("user2")
u1 = UserFactory(username="user1")
u2 = UserFactory(username="user2")
u1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
u2.user_permissions.add(*Permission.objects.filter(codename="view_document"))
@@ -1641,8 +1641,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
self.assertEqual(r.data["count"], 1)
def test_search_sorting(self) -> None:
u1 = User.objects.create_user("user1")
u2 = User.objects.create_user("user2")
u1 = UserFactory(username="user1")
u2 = UserFactory(username="user2")
c1 = Correspondent.objects.create(name="corres Ax")
c2 = Correspondent.objects.create(name="corres Cx")
c3 = Correspondent.objects.create(name="corres Bx")
@@ -1892,8 +1892,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
pk=5,
)
user1 = User.objects.create_user("bank user1")
user2 = User.objects.create_superuser("user2")
user1 = UserFactory(username="bank user1")
user2 = UserFactory(username="user2", superuser=True)
group1 = Group.objects.create(name="bank group1")
Group.objects.create(name="group2")
@@ -2018,8 +2018,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
self.assertEqual(returned.get(root.id), "latest content")
def test_global_search_filters_owned_mail_objects(self) -> None:
user1 = User.objects.create_user("mail-search-user")
user2 = User.objects.create_user("other-mail-search-user")
user1 = UserFactory(username="mail-search-user")
user2 = UserFactory(username="other-mail-search-user")
user1.user_permissions.add(
Permission.objects.get(codename="view_mailaccount"),
Permission.objects.get(codename="view_mailrule"),
+4 -6
View File
@@ -6,7 +6,6 @@ from pathlib import Path
from unittest import mock
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import override_settings
from django.utils import timezone
from rest_framework import status
@@ -16,6 +15,7 @@ from documents.models import PaperlessTask
from documents.permissions import has_system_status_permission
from paperless import version
from paperless_testing.factories import PaperlessTaskFactory
from paperless_testing.factories import UserFactory
class TestSystemStatus(APITestCase):
@@ -23,9 +23,7 @@ class TestSystemStatus(APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(
username="temp_admin",
)
self.user = UserFactory(username="temp_admin", superuser=True)
self.tmp_dir = Path(tempfile.mkdtemp())
self.override = override_settings(MEDIA_ROOT=self.tmp_dir)
self.override.enable()
@@ -96,7 +94,7 @@ class TestSystemStatus(APITestCase):
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
self.assertEqual(response["WWW-Authenticate"], "Token")
normal_user = User.objects.create_user(username="normal_user")
normal_user = UserFactory(username="normal_user")
self.client.force_login(normal_user)
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
@@ -107,7 +105,7 @@ class TestSystemStatus(APITestCase):
response = self.client.get(self.ENDPOINT)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
user = User.objects.create_user(username="status_user")
user = UserFactory(username="status_user")
user.user_permissions.add(
Permission.objects.get(codename="view_system_monitoring"),
)
+8 -12
View File
@@ -26,7 +26,6 @@ from paperless_testing.factories import PaperlessTaskFactory
pytestmark = pytest.mark.api
ENDPOINT = "/api/tasks/"
ACCEPT_V10 = "application/json; version=10"
ACCEPT_V9 = "application/json; version=9"
@@ -346,21 +345,18 @@ class TestGetTasksV10:
self,
admin_user: User,
regular_user: User,
user_client: APIClient,
) -> None:
"""Regular users see their own tasks and unowned (system) tasks; other users' tasks are hidden."""
regular_user.user_permissions.add(
Permission.objects.get(codename="view_paperlesstask"),
)
client = APIClient()
client.force_authenticate(user=regular_user)
client.credentials(HTTP_ACCEPT=ACCEPT_V10)
PaperlessTaskFactory(owner=admin_user) # other user — not visible
unowned_task = PaperlessTaskFactory() # unowned (system task) — visible
own_task = PaperlessTaskFactory(owner=regular_user)
response = client.get(ENDPOINT)
response = user_client.get(ENDPOINT)
assert response.status_code == status.HTTP_200_OK
assert response.data["count"] == 2
@@ -732,19 +728,19 @@ class TestAcknowledge:
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_succeeds_with_change_permission(self, regular_user: User) -> None:
def test_succeeds_with_change_permission(
self,
regular_user: User,
user_client: APIClient,
) -> None:
"""Users granted change_paperlesstask permission can acknowledge tasks."""
regular_user.user_permissions.add(
Permission.objects.get(codename="change_paperlesstask"),
)
regular_user.save()
client = APIClient()
client.force_authenticate(user=regular_user)
client.credentials(HTTP_ACCEPT=ACCEPT_V10)
task = PaperlessTaskFactory()
response = client.post(
response = user_client.post(
ENDPOINT + "acknowledge/",
{"tasks": [task.id]},
format="json",
+6 -6
View File
@@ -1,20 +1,20 @@
from datetime import date
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.core.cache import cache
from rest_framework import status
from rest_framework.test import APITestCase
from documents.models import Document
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestTrashAPI(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_user(username="temp_admin")
self.user = UserFactory(username="temp_admin")
self.user.user_permissions.add(*Permission.objects.all())
self.client.force_authenticate(user=self.user)
cache.clear()
@@ -70,7 +70,7 @@ class TestTrashAPI(DirectoriesMixin, APITestCase):
self.assertEqual(Document.global_objects.count(), 0)
def test_trash_list_requires_global_document_view_permission(self) -> None:
user = User.objects.create_user(username="trash_owner")
user = UserFactory(username="trash_owner")
document = Document.objects.create(title="Owned", owner=user)
document.delete()
self.client.force_authenticate(user)
@@ -140,7 +140,7 @@ class TestTrashAPI(DirectoriesMixin, APITestCase):
created=date(2023, 1, 2),
)
document_not_owned.delete()
user2 = User.objects.create_user(username="user2")
user2 = UserFactory(username="user2")
document_u2 = Document.objects.create(
title="Title3",
content="content3",
@@ -158,7 +158,7 @@ class TestTrashAPI(DirectoriesMixin, APITestCase):
self.assertEqual(resp.data["results"][1]["id"], document_u1.pk)
# superuser sees all documents
superuser = User.objects.create_superuser(username="superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
resp = self.client.get("/api/trash/")
self.assertEqual(resp.status_code, status.HTTP_200_OK)
@@ -174,7 +174,7 @@ class TestTrashAPI(DirectoriesMixin, APITestCase):
- 403 Forbidden
"""
user2 = User.objects.create_user(username="user2")
user2 = UserFactory(username="user2")
document = Document.objects.create(
title="Title",
content="content",
+4 -4
View File
@@ -1,13 +1,13 @@
import json
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import override_settings
from rest_framework import status
from rest_framework.test import APITestCase
from paperless.version import __full_version_str__
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestApiUiSettings(DirectoriesMixin, APITestCase):
@@ -15,7 +15,7 @@ class TestApiUiSettings(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.test_user = User.objects.create_superuser(username="test")
self.test_user = UserFactory(username="test", superuser=True)
self.test_user.first_name = "Test"
self.test_user.last_name = "User"
self.test_user.save()
@@ -91,7 +91,7 @@ class TestApiUiSettings(DirectoriesMixin, APITestCase):
)
def test_api_set_ui_settings_insufficient_global_permissions(self) -> None:
not_superuser = User.objects.create_user(username="test_not_superuser")
not_superuser = UserFactory(username="test_not_superuser")
self.client.force_authenticate(user=not_superuser)
settings = {
@@ -111,7 +111,7 @@ class TestApiUiSettings(DirectoriesMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_api_set_ui_settings_sufficient_global_permissions(self) -> None:
not_superuser = User.objects.create_user(username="test_not_superuser")
not_superuser = UserFactory(username="test_not_superuser")
not_superuser.user_permissions.add(
*Permission.objects.filter(codename__contains="uisettings"),
)
+2 -1
View File
@@ -15,6 +15,7 @@ from documents.models import Workflow
from documents.models import WorkflowAction
from documents.models import WorkflowTrigger
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestApiWorkflows(DirectoriesMixin, APITestCase):
@@ -25,7 +26,7 @@ class TestApiWorkflows(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
user = User.objects.create_superuser(username="temp_admin")
user = UserFactory(username="temp_admin", superuser=True)
self.client.force_authenticate(user=user)
self.user2 = User.objects.create(username="user2")
self.user3 = User.objects.create(username="user3")
+2 -1
View File
@@ -35,6 +35,7 @@ from documents.tests.utils import FileSystemAssertsMixin
from documents.tests.utils import GetConsumerMixin
from paperless_mail.models import MailRule
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class _BaseNewStyleParser:
@@ -769,7 +770,7 @@ class TestConsumer(
original_modified = timezone.now() - datetime.timedelta(days=1)
Document.objects.filter(pk=root_doc.pk).update(modified=original_modified)
actor = User.objects.create_user(
actor = UserFactory(
username="actor",
email="actor@example.com",
password="password",
+2 -2
View File
@@ -8,7 +8,6 @@ from unittest import mock
import pytest
from auditlog.context import disable_auditlog
from django.conf import settings
from django.contrib.auth.models import User
from django.db import DatabaseError
from django.db import connection
from django.test import TestCase
@@ -33,6 +32,7 @@ from documents.tasks import empty_trash
from documents.tests.utils import FileSystemAssertsMixin
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import UserFactory
class TestFileHandling(DirectoriesMixin, FileSystemAssertsMixin, TestCase):
@@ -1323,7 +1323,7 @@ class TestFilenameGeneration(DirectoriesMixin, TestCase):
- Document without owner returns "none"
"""
u1 = User.objects.create_user("user1")
u1 = UserFactory(username="user1")
owned_doc = Document.objects.create(
title="The Title",
@@ -3,7 +3,6 @@ from unittest import mock
from auditlog.models import LogEntry
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase
from rest_framework import status
@@ -12,6 +11,7 @@ from rest_framework.test import APITestCase
from documents.bulk_edit import merge_as_versions
from documents.models import Document
from documents.serialisers import MergeDocumentsAsVersionsSerializer
from paperless_testing.factories import UserFactory
class TestMergeDocumentsAsVersionsSerializer(TestCase):
@@ -294,7 +294,7 @@ class TestMergeDocumentsAsVersions(TestCase):
@mock.patch("documents.bulk_edit.bulk_update_documents.apply_async")
@mock.patch("documents.search.get_backend")
def test_writes_audit_log_entry(self, *_mocks) -> None:
user = User.objects.create_user(username="merger")
user = UserFactory(username="merger")
root = Document.objects.create(checksum="A", title="Root")
source = Document.objects.create(checksum="B", title="Source")
LogEntry.objects.all().delete()
@@ -335,7 +335,7 @@ class TestMergeDocumentsAsVersions(TestCase):
class TestMergeDocumentsAsVersionsAPI(APITestCase):
def setUp(self) -> None:
self.user = User.objects.create_user(username="user")
self.user = UserFactory(username="user")
self.user.user_permissions.add(
Permission.objects.get(codename="change_document"),
Permission.objects.get(codename="view_document"),
@@ -382,7 +382,7 @@ class TestMergeDocumentsAsVersionsAPI(APITestCase):
@mock.patch("documents.views.bulk_edit.merge_as_versions")
def test_requires_change_permission(self, merge_mock) -> None:
merge_mock.__name__ = "merge_as_versions"
user = User.objects.create_user(username="no-change")
user = UserFactory(username="no-change")
self.doc1.owner = user
self.doc1.save()
self.doc2.owner = user
@@ -405,7 +405,7 @@ class TestMergeDocumentsAsVersionsAPI(APITestCase):
def test_requires_delete_permission(self, merge_mock) -> None:
merge_mock.__name__ = "merge_as_versions"
# Owns them and may change them, but may not make them stop being documents
user = User.objects.create_user(username="no-delete")
user = UserFactory(username="no-delete")
user.user_permissions.add(
Permission.objects.get(codename="change_document"),
Permission.objects.get(codename="view_document"),
@@ -8,7 +8,6 @@ import pytest
from django.contrib.auth.models import AnonymousUser
from django.contrib.auth.models import Group
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import override_settings
from guardian.shortcuts import assign_perm
from rest_framework.test import APIClient
@@ -30,6 +29,7 @@ from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import DocumentTypeFactory
from paperless_testing.factories import StoragePathFactory
from paperless_testing.factories import TagFactory
from paperless_testing.factories import UserFactory
if TYPE_CHECKING:
from paperless_testing.dirs import PaperlessDirs
@@ -51,8 +51,8 @@ def assert_visible_document_ids(actual_ids, *, expected_visible, expected_hidden
@pytest.mark.django_db
class TestPermittedDocumentIdsSecurity:
def test_owner_sees_own_document(self):
user = User.objects.create_user(username="alice")
stranger = User.objects.create_user(username="mallory")
user = UserFactory(username="alice")
stranger = UserFactory(username="mallory")
owned = DocumentFactory(owner=user)
strangers_doc = DocumentFactory(owner=stranger)
@@ -65,7 +65,7 @@ class TestPermittedDocumentIdsSecurity:
)
def test_unowned_document_visible_to_everyone(self):
user = User.objects.create_user(username="alice")
user = UserFactory(username="alice")
unowned = DocumentFactory(owner=None)
assert_visible_document_ids(
@@ -75,9 +75,9 @@ class TestPermittedDocumentIdsSecurity:
)
def test_explicit_user_permission_grants_visibility(self):
grantee = User.objects.create_user(username="alice")
stranger = User.objects.create_user(username="mallory")
owner = User.objects.create_user(username="owner")
grantee = UserFactory(username="alice")
stranger = UserFactory(username="mallory")
owner = UserFactory(username="owner")
shared = DocumentFactory(owner=owner)
not_shared = DocumentFactory(owner=owner)
assign_perm("view_document", grantee, shared)
@@ -94,9 +94,9 @@ class TestPermittedDocumentIdsSecurity:
)
def test_explicit_group_permission_grants_visibility_to_members_only(self):
owner = User.objects.create_user(username="owner")
member = User.objects.create_user(username="member")
non_member = User.objects.create_user(username="non_member")
owner = UserFactory(username="owner")
member = UserFactory(username="member")
non_member = UserFactory(username="non_member")
group = Group.objects.create(name="finance")
member.groups.add(group)
shared = DocumentFactory(owner=owner)
@@ -114,7 +114,7 @@ class TestPermittedDocumentIdsSecurity:
)
def test_soft_deleted_document_excluded_by_default(self):
owner = User.objects.create_user(username="owner")
owner = UserFactory(username="owner")
doc = DocumentFactory(owner=owner)
doc.delete() # soft delete
doc.refresh_from_db()
@@ -130,8 +130,8 @@ class TestPermittedDocumentIdsSecurity:
)
def test_superuser_sees_everything_including_no_perm_documents(self):
superuser = User.objects.create_superuser(username="root")
owner = User.objects.create_user(username="owner")
superuser = UserFactory(username="root", superuser=True)
owner = UserFactory(username="owner")
doc = DocumentFactory(owner=owner)
assert_visible_document_ids(
@@ -141,7 +141,7 @@ class TestPermittedDocumentIdsSecurity:
)
def test_anonymous_user_sees_only_unowned_documents(self):
owner = User.objects.create_user(username="owner")
owner = UserFactory(username="owner")
owned = DocumentFactory(owner=owner)
unowned = DocumentFactory(owner=None)
@@ -155,7 +155,7 @@ class TestPermittedDocumentIdsSecurity:
@pytest.mark.django_db
class TestPermittedDocumentIdsIncludeDeleted:
def test_include_deleted_true_reveals_soft_deleted_owned_document(self):
owner = User.objects.create_user(username="owner")
owner = UserFactory(username="owner")
doc = DocumentFactory(owner=owner)
doc.delete()
@@ -166,8 +166,8 @@ class TestPermittedDocumentIdsIncludeDeleted:
)
def test_include_deleted_true_still_respects_permission_boundary(self):
owner = User.objects.create_user(username="owner")
stranger = User.objects.create_user(username="mallory")
owner = UserFactory(username="owner")
stranger = UserFactory(username="mallory")
doc = DocumentFactory(owner=owner)
doc.delete()
@@ -195,8 +195,8 @@ class TestAiChatAllDocumentsPermissionBoundary:
def test_chat_all_documents_excludes_unshared_document(self, mock_stream_chat):
mock_stream_chat.return_value = iter([b"data"])
owner = User.objects.create_user(username="owner")
asker = User.objects.create_user(username="asker")
owner = UserFactory(username="owner")
asker = UserFactory(username="asker")
asker.user_permissions.add(
*Permission.objects.filter(codename="view_document"),
)
@@ -223,8 +223,8 @@ class TestAiChatAllDocumentsPermissionBoundary:
@pytest.mark.django_db
class TestDuplicateDocumentsPermissionBoundary:
def test_get_viewable_duplicates_includes_soft_deleted_but_respects_perms(self):
owner = User.objects.create_user(username="owner")
stranger = User.objects.create_user(username="mallory")
owner = UserFactory(username="owner")
stranger = UserFactory(username="mallory")
original = DocumentFactory(owner=owner, checksum="dupe-checksum")
dup_visible = DocumentFactory(owner=owner, checksum="dupe-checksum")
dup_hidden = DocumentFactory(owner=owner, checksum="dupe-checksum")
@@ -241,9 +241,9 @@ class TestDuplicateDocumentsPermissionBoundary:
@pytest.mark.django_db
class TestPermittedDocumentIdsArbitraryPermission:
def test_change_document_permission_is_distinct_from_view(self):
owner = User.objects.create_user(username="owner")
viewer_only = User.objects.create_user(username="viewer")
editor = User.objects.create_user(username="editor")
owner = UserFactory(username="owner")
viewer_only = UserFactory(username="viewer")
editor = UserFactory(username="editor")
doc = DocumentFactory(owner=owner)
assign_perm("view_document", viewer_only, doc)
assign_perm("change_document", editor, doc)
@@ -261,8 +261,8 @@ class TestPermittedDocumentIdsArbitraryPermission:
)
def test_qualified_permission_string_is_normalized_to_codename(self):
owner = User.objects.create_user(username="owner")
editor = User.objects.create_user(username="editor")
owner = UserFactory(username="owner")
editor = UserFactory(username="editor")
doc = DocumentFactory(owner=owner)
assign_perm("change_document", editor, doc)
@@ -273,9 +273,9 @@ class TestPermittedDocumentIdsArbitraryPermission:
)
def test_delete_permission_with_include_deleted_for_trash_restore(self):
owner = User.objects.create_user(username="owner")
stranger = User.objects.create_user(username="mallory")
view_only = User.objects.create_user(username="viewer")
owner = UserFactory(username="owner")
stranger = UserFactory(username="mallory")
view_only = UserFactory(username="viewer")
doc = DocumentFactory(owner=owner)
assign_perm("view_document", view_only, doc)
doc.delete()
@@ -311,8 +311,8 @@ class TestEmailDocumentPermissionBoundary:
self,
rest_api_client,
):
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
requester.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -343,8 +343,8 @@ class TestBulkEditChangePermissionBoundary:
# permitted document must not be partially applied just because it
# was bundled with a forbidden one, proving the endpoint checks
# every document in the batch rather than only the first/last.
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
# grant the global change_document permission so the object-level
# check (not the global has_perm check) is what's under test
requester.user_permissions.add(
@@ -376,8 +376,8 @@ class TestBulkDownloadPermissionChecksRootDocument:
rest_api_client: APIClient,
paperless_dirs: PaperlessDirs,
) -> None:
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
root = DocumentFactory(owner=owner)
root.source_path.write_bytes(b"%PDF-1.4 test")
assign_perm("view_document", requester, root)
@@ -396,8 +396,8 @@ class TestBulkDownloadPermissionChecksRootDocument:
rest_api_client: APIClient,
paperless_dirs: PaperlessDirs,
) -> None:
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
requester.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -424,7 +424,7 @@ class TestBulkDownloadPermissionChecksRootDocument:
# root-or-version bug; a user with no grant at all (the old
# `stranger` case) can't tell the two apart, since they're denied
# either way.
version_only_grantee = User.objects.create_user(username="version_only_grantee")
version_only_grantee = UserFactory(username="version_only_grantee")
version_only_grantee.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -447,8 +447,8 @@ class TestTrashRestorePermissionBoundary:
self,
rest_api_client,
):
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
requester.user_permissions.add(
Permission.objects.get(codename="delete_document"),
)
@@ -468,8 +468,8 @@ class TestTrashRestorePermissionBoundary:
self,
rest_api_client,
):
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
requester.user_permissions.add(
Permission.objects.get(codename="delete_document"),
)
@@ -486,8 +486,8 @@ class TestTrashRestorePermissionBoundary:
assert response.status_code == HTTPStatus.OK
def test_restore_requires_global_delete_permission(self, rest_api_client):
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
rest_api_client.force_authenticate(user=requester)
doc = DocumentFactory(owner=owner)
assign_perm("delete_document", requester, doc)
@@ -515,8 +515,8 @@ class TestTrashViewExcludesExplicitlyGrantedDocuments:
"""
def test_explicit_grant_does_not_leak_trashed_document(self, rest_api_client):
owner = User.objects.create_user(username="trash_owner")
grantee = User.objects.create_user(username="trash_grantee")
owner = UserFactory(username="trash_owner")
grantee = UserFactory(username="trash_grantee")
grantee.user_permissions.add(
Permission.objects.get(codename="view_document"),
)
@@ -544,8 +544,8 @@ class TestTrashViewExcludesExplicitlyGrantedDocuments:
)
class TestPermittedObjectIdsGenericModels:
def test_owner_sees_own_object(self, model, factory, perm):
owner = User.objects.create_user(username=f"owner_{model.__name__}")
stranger = User.objects.create_user(username=f"stranger_{model.__name__}")
owner = UserFactory(username=f"owner_{model.__name__}")
stranger = UserFactory(username=f"stranger_{model.__name__}")
owned = factory(owner=owner)
strangers = factory(owner=stranger)
@@ -558,12 +558,12 @@ class TestPermittedObjectIdsGenericModels:
@pytest.mark.parametrize("is_superuser", [False, True])
def test_inactive_user_sees_nothing(self, model, factory, perm, is_superuser):
suffix = f"{model.__name__}_{is_superuser}"
user = User.objects.create_user(
user = UserFactory(
username=f"inactive_{suffix}",
is_active=False,
is_superuser=is_superuser,
)
other = User.objects.create_user(username=f"other_{suffix}")
other = UserFactory(username=f"other_{suffix}")
granted = factory(owner=other)
assign_perm(perm, user, granted)
@@ -578,7 +578,7 @@ class TestPermittedObjectIdsGenericModels:
)
def test_unowned_object_visible_to_everyone(self, model, factory, perm):
user = User.objects.create_user(username=f"user_{model.__name__}")
user = UserFactory(username=f"user_{model.__name__}")
unowned = factory(owner=None)
assert_visible_document_ids(
@@ -588,9 +588,9 @@ class TestPermittedObjectIdsGenericModels:
)
def test_explicit_permission_grants_visibility(self, model, factory, perm):
owner = User.objects.create_user(username=f"owner2_{model.__name__}")
grantee = User.objects.create_user(username=f"grantee_{model.__name__}")
stranger = User.objects.create_user(username=f"stranger2_{model.__name__}")
owner = UserFactory(username=f"owner2_{model.__name__}")
grantee = UserFactory(username=f"grantee_{model.__name__}")
stranger = UserFactory(username=f"stranger2_{model.__name__}")
shared = factory(owner=owner)
not_shared = factory(owner=owner)
assign_perm(perm, grantee, shared)
@@ -612,9 +612,9 @@ class TestPermittedObjectIdsGenericModels:
factory,
perm,
):
owner = User.objects.create_user(username=f"owner3_{model.__name__}")
member = User.objects.create_user(username=f"member_{model.__name__}")
non_member = User.objects.create_user(username=f"nonmember_{model.__name__}")
owner = UserFactory(username=f"owner3_{model.__name__}")
member = UserFactory(username=f"member_{model.__name__}")
non_member = UserFactory(username=f"nonmember_{model.__name__}")
group = Group.objects.create(name=f"group_{model.__name__}")
member.groups.add(group)
shared = factory(owner=owner)
@@ -632,8 +632,8 @@ class TestPermittedObjectIdsGenericModels:
)
def test_superuser_sees_everything(self, model, factory, perm):
superuser = User.objects.create_superuser(username=f"root_{model.__name__}")
owner = User.objects.create_user(username=f"owner4_{model.__name__}")
superuser = UserFactory(username=f"root_{model.__name__}", superuser=True)
owner = UserFactory(username=f"owner4_{model.__name__}")
obj = factory(owner=owner)
assert_visible_document_ids(
@@ -646,8 +646,8 @@ class TestPermittedObjectIdsGenericModels:
@pytest.mark.django_db
class TestMatchingRespectsObjectPermissions:
def test_match_tags_only_considers_tags_visible_to_user(self):
owner = User.objects.create_user(username="tag_owner")
classifying_user = User.objects.create_user(username="classifier_user")
owner = UserFactory(username="tag_owner")
classifying_user = UserFactory(username="classifier_user")
visible_tag = TagFactory(
owner=owner,
match="invoice",
@@ -667,8 +667,8 @@ class TestMatchingRespectsObjectPermissions:
assert hidden_tag.pk not in matched_ids
def test_match_correspondents_only_considers_correspondents_visible_to_user(self):
owner = User.objects.create_user(username="correspondent_owner")
classifying_user = User.objects.create_user(username="classifier_user2")
owner = UserFactory(username="correspondent_owner")
classifying_user = UserFactory(username="classifier_user2")
visible_correspondent = CorrespondentFactory(
owner=owner,
match="invoice",
@@ -688,8 +688,8 @@ class TestMatchingRespectsObjectPermissions:
assert hidden_correspondent.pk not in matched_ids
def test_match_document_types_only_considers_document_types_visible_to_user(self):
owner = User.objects.create_user(username="document_type_owner")
classifying_user = User.objects.create_user(username="classifier_user3")
owner = UserFactory(username="document_type_owner")
classifying_user = UserFactory(username="classifier_user3")
visible_document_type = DocumentTypeFactory(
owner=owner,
match="invoice",
@@ -709,8 +709,8 @@ class TestMatchingRespectsObjectPermissions:
assert hidden_document_type.pk not in matched_ids
def test_match_storage_paths_only_considers_storage_paths_visible_to_user(self):
owner = User.objects.create_user(username="storage_path_owner")
classifying_user = User.objects.create_user(username="classifier_user4")
owner = UserFactory(username="storage_path_owner")
classifying_user = UserFactory(username="classifier_user4")
visible_storage_path = StoragePathFactory(
owner=owner,
match="invoice",
@@ -733,9 +733,9 @@ class TestMatchingRespectsObjectPermissions:
@pytest.mark.django_db
class TestBulkEditObjectsApplyToAllPermissionBoundary:
def test_apply_to_all_tags_excludes_unpermitted_tag(self, rest_api_client):
owner = User.objects.create_user(username="tags_owner")
requester = User.objects.create_user(username="tags_requester")
new_owner = User.objects.create_user(username="tags_new_owner")
owner = UserFactory(username="tags_owner")
requester = UserFactory(username="tags_requester")
new_owner = UserFactory(username="tags_new_owner")
# grant the global change_tag permission so the object-level
# filtering (not the global has_perm check) is what's under test
requester.user_permissions.add(
@@ -773,8 +773,8 @@ class TestBulkEditObjectsApplyToAllPermissionBoundary:
request rather than being silently skipped. Editing permissions is
limited to the owner, same as documents.
"""
owner = User.objects.create_user(username="shared_tags_owner")
requester = User.objects.create_user(username="shared_tags_requester")
owner = UserFactory(username="shared_tags_owner")
requester = UserFactory(username="shared_tags_requester")
requester.user_permissions.add(
Permission.objects.get(codename="change_tag"),
)
@@ -833,9 +833,9 @@ class TestBulkEditObjectsTagDescendantPartialPermission:
would pass/fail based on FK cascade behavior, not on whether the
descendant-expansion logic itself respected per-object permissions.
"""
owner = User.objects.create_user(username="tag_hierarchy_owner")
requester = User.objects.create_user(username="tag_hierarchy_requester")
new_owner = User.objects.create_user(username="tag_hierarchy_new_owner")
owner = UserFactory(username="tag_hierarchy_owner")
requester = UserFactory(username="tag_hierarchy_requester")
new_owner = UserFactory(username="tag_hierarchy_new_owner")
# global change_tag permission so the has_perm() gate passes and the
# object-level permitted_object_ids filtering is what's under test
requester.user_permissions.add(
@@ -892,7 +892,7 @@ class TestRestrictQuerysetToVisible:
- The queryset is returned unfiltered, rather than
permitted_object_ids(None, ...)'s narrower "unowned rows only"
"""
owner = User.objects.create_user(username="vis_none_owner")
owner = UserFactory(username="vis_none_owner")
tag = TagFactory(owner=owner)
visible = restrict_queryset_to_visible(Tag.objects.all(), None, "view_tag")
@@ -909,8 +909,8 @@ class TestRestrictQuerysetToVisible:
- The queryset is returned unfiltered, skipping the permission
lookup entirely
"""
superuser = User.objects.create_superuser(username="vis_active_super")
owner = User.objects.create_user(username="vis_active_super_owner")
superuser = UserFactory(username="vis_active_super", superuser=True)
owner = UserFactory(username="vis_active_super_owner")
tag = TagFactory(owner=owner)
visible = restrict_queryset_to_visible(
@@ -932,7 +932,7 @@ class TestRestrictQuerysetToVisible:
deactivation has to win over the superuser shortcut, matching
permitted_object_ids's own ordering
"""
user = User.objects.create_user(
user = UserFactory(
username="vis_inactive_super",
is_active=False,
is_superuser=True,
@@ -953,8 +953,8 @@ class TestRestrictQuerysetToVisible:
THEN:
- Only the rows permitted_object_ids() reports are visible
"""
user = User.objects.create_user(username="vis_regular")
other = User.objects.create_user(username="vis_regular_other")
user = UserFactory(username="vis_regular")
other = UserFactory(username="vis_regular_other")
own = TagFactory(owner=user)
hidden = TagFactory(owner=other)
@@ -1,11 +1,11 @@
import pytest
from django.contrib.auth.models import User
from guardian.shortcuts import assign_perm
from rest_framework.test import APIRequestFactory
from documents.filters import PermittedObjectsFilter
from documents.models import Tag
from paperless_testing.factories import TagFactory
from paperless_testing.factories import UserFactory
class _DummyView:
@@ -15,8 +15,8 @@ class _DummyView:
@pytest.mark.django_db
class TestPermittedObjectsFilter:
def test_superuser_bypasses_filtering_entirely(self):
superuser = User.objects.create_superuser(username="root")
owner = User.objects.create_user(username="owner")
superuser = UserFactory(username="root", superuser=True)
owner = UserFactory(username="owner")
TagFactory(owner=owner)
request = APIRequestFactory().get("/")
request.user = superuser
@@ -29,8 +29,8 @@ class TestPermittedObjectsFilter:
assert result.count() == Tag.objects.count()
def test_non_superuser_sees_only_owned_unowned_and_granted(self):
owner = User.objects.create_user(username="owner")
grantee = User.objects.create_user(username="grantee")
owner = UserFactory(username="owner")
grantee = UserFactory(username="grantee")
owned = TagFactory(owner=grantee)
unowned = TagFactory(owner=None)
granted = TagFactory(owner=owner)
@@ -49,8 +49,8 @@ class TestPermittedObjectsFilter:
assert hidden.pk not in visible_ids
def test_include_granted_false_excludes_explicitly_shared_objects(self):
owner = User.objects.create_user(username="owner2")
grantee = User.objects.create_user(username="grantee2")
owner = UserFactory(username="owner2")
grantee = UserFactory(username="grantee2")
owned = TagFactory(owner=grantee)
granted = TagFactory(owner=owner)
assign_perm("view_tag", grantee, granted)
@@ -74,14 +74,14 @@ class TestPermittedObjectsFilter:
[("inactive", False), ("inactive_super", True)],
)
def test_inactive_user_sees_nothing(self, username: str, *, is_superuser: bool):
user = User.objects.create_user(
user = UserFactory(
username=username,
is_active=False,
is_superuser=is_superuser,
)
TagFactory(owner=None)
TagFactory(owner=user)
granted = TagFactory(owner=User.objects.create_user(username=f"o_{username}"))
granted = TagFactory(owner=UserFactory(username=f"o_{username}"))
assign_perm("view_tag", user, granted)
request = APIRequestFactory().get("/")
request.user = user
@@ -94,7 +94,7 @@ class TestPermittedObjectsFilter:
assert result.count() == 0
def test_inactive_user_sees_nothing_with_include_granted_false(self):
user = User.objects.create_user(username="inactive_owner", is_active=False)
user = UserFactory(username="inactive_owner", is_active=False)
TagFactory(owner=user)
TagFactory(owner=None)
request = APIRequestFactory().get("/")
@@ -22,6 +22,7 @@ from documents.tasks import build_share_link_bundle
from documents.tasks import cleanup_expired_share_link_bundles
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import DocumentFactory
from paperless_testing.factories import UserFactory
class ShareLinkBundleAPITests(DirectoriesMixin, APITestCase):
@@ -29,7 +30,7 @@ class ShareLinkBundleAPITests(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="bundle_admin")
self.user = UserFactory(username="bundle_admin", superuser=True)
self.client.force_authenticate(self.user)
self.document = DocumentFactory.create()
@@ -55,8 +56,8 @@ class ShareLinkBundleAPITests(DirectoriesMixin, APITestCase):
self,
delay_mock,
) -> None:
owner = User.objects.create_user(username="document_owner")
requester = User.objects.create_user(username="bundle_creator")
owner = UserFactory(username="document_owner")
requester = UserFactory(username="bundle_creator")
requester.user_permissions.add(
Permission.objects.get(codename="add_sharelinkbundle"),
)
+4 -4
View File
@@ -1,7 +1,6 @@
from unittest import mock
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework.test import APITestCase
@@ -14,12 +13,13 @@ from documents.models import WorkflowTrigger
from documents.serialisers import TagSerializer
from documents.signals.handlers import run_workflows
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestTagHierarchyPermissions(APITestCase):
def test_children_only_include_visible_tags(self) -> None:
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
owner = UserFactory(username="owner")
requester = UserFactory(username="requester")
requester.user_permissions.add(
Permission.objects.get(codename="view_tag"),
)
@@ -49,7 +49,7 @@ class TestTagHierarchyPermissions(APITestCase):
class TestTagHierarchy(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(username="admin")
self.user = UserFactory(username="admin", superuser=True)
self.client.force_authenticate(user=self.user)
self.parent = Tag.objects.create(name="Parent")
+3 -2
View File
@@ -18,6 +18,7 @@ from documents.signals.handlers import task_postrun_handler
from documents.signals.handlers import task_prerun_handler
from documents.signals.handlers import task_revoked_handler
from paperless_testing.factories import PaperlessTaskFactory
from paperless_testing.factories import UserFactory
@pytest.fixture
@@ -34,8 +35,8 @@ def consume_input_doc():
@pytest.fixture
def consume_overrides(django_user_model):
user = django_user_model.objects.create_user(username="testuser")
def consume_overrides():
user = UserFactory(username="testuser")
overrides = mock.MagicMock(spec=DocumentMetadataOverrides)
overrides.owner_id = user.id
return overrides
+9 -8
View File
@@ -34,6 +34,7 @@ from paperless.models import ApplicationConfiguration
from paperless_ai.exceptions import LLMProviderError
from paperless_ai.exceptions import LLMTimeoutError
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestViews(DirectoriesMixin, TestCase):
@@ -43,7 +44,7 @@ class TestViews(DirectoriesMixin, TestCase):
ApplicationConfiguration.objects.get_or_create()
def setUp(self) -> None:
self.user = User.objects.create_user("testuser")
self.user = UserFactory(username="testuser")
super().setUp()
def test_login_redirect(self) -> None:
@@ -338,7 +339,7 @@ class TestViews(DirectoriesMixin, TestCase):
class TestAISuggestions(DirectoriesMixin, TestCase):
def setUp(self) -> None:
self.user = User.objects.create_superuser(username="testuser")
self.user = UserFactory(username="testuser", superuser=True)
self.document = Document.objects.create(
title="Test Document",
filename="test.pdf",
@@ -425,9 +426,9 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
requester; the invisible tag id does not leak into either the
matched or suggested tags
"""
tag_owner = User.objects.create_user(username="cache_tag_owner")
tag_owner = UserFactory(username="cache_tag_owner")
invisible_tag = Tag.objects.create(name="cache_restricted", owner=tag_owner)
requester = User.objects.create_user(username="cache_requester")
requester = UserFactory(username="cache_requester")
requester.user_permissions.add(
*Permission.objects.filter(
codename__in=["view_document", "change_document", "view_tag"],
@@ -637,7 +638,7 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
- The classification runs with the second user's visibility
context without evicting the first user's result
"""
second_user = User.objects.create_superuser(username="second_user")
second_user = UserFactory(username="second_user", superuser=True)
empty_choices = {
"tags": {"existing_ids": [], "new_names": []},
"correspondents": {"existing_ids": [], "new_names": []},
@@ -875,9 +876,9 @@ class TestAISuggestions(DirectoriesMixin, TestCase):
permission filtering survives the full request path
- it does not appear in either the matched or suggested tags
"""
tag_owner = User.objects.create_user(username="tagowner")
tag_owner = UserFactory(username="tagowner")
invisible_tag = Tag.objects.create(name="restricted", owner=tag_owner)
requester = User.objects.create_user(username="requester")
requester = UserFactory(username="requester")
requester.user_permissions.add(
*Permission.objects.filter(
codename__in=["view_document", "change_document", "view_tag"],
@@ -956,7 +957,7 @@ class TestAIChatStreamingView(DirectoriesMixin, TestCase):
ENDPOINT = "/api/documents/chat/"
def setUp(self) -> None:
self.user = User.objects.create_user(username="testuser", password="pass")
self.user = UserFactory(username="testuser", password="pass")
self.client.force_login(user=self.user)
self.document = Document.objects.create(
title="Test Document",
+12 -11
View File
@@ -71,6 +71,7 @@ from documents.workflows.actions import execute_password_removal_action
from paperless_mail.models import MailAccount
from paperless_mail.models import MailRule
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestWorkflows(
@@ -1952,7 +1953,7 @@ class TestWorkflows(
original_filename="sample.pdf",
)
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
@@ -1982,7 +1983,7 @@ class TestWorkflows(
w.actions.add(action)
w.save()
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
test_file = shutil.copy(
self.SAMPLE_DIR / "simple.pdf",
@@ -2040,7 +2041,7 @@ class TestWorkflows(
value_text="existing value",
)
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
@@ -2084,7 +2085,7 @@ class TestWorkflows(
)
CustomFieldInstance.objects.create(document=doc, field=self.cf1)
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
@@ -2134,7 +2135,7 @@ class TestWorkflows(
assign_perm("documents.view_document", self.group1, doc)
assign_perm("documents.change_document", self.group1, doc)
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
@@ -2905,7 +2906,7 @@ class TestWorkflows(
assign_perm("documents.view_document", self.group1, doc)
assign_perm("documents.change_document", self.group1, doc)
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
@@ -2977,7 +2978,7 @@ class TestWorkflows(
doc.refresh_from_db()
doc.tags.set([self.t1, self.t2])
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
f"/api/documents/{doc.id}/",
@@ -3041,7 +3042,7 @@ class TestWorkflows(
doc.refresh_from_db()
doc.tags.set([self.t1])
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
f"/api/documents/{doc.id}/",
@@ -3102,7 +3103,7 @@ class TestWorkflows(
assign_perm("documents.view_document", self.group1, doc)
assign_perm("documents.change_document", self.group1, doc)
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
@@ -3395,7 +3396,7 @@ class TestWorkflows(
original_filename="sample.pdf",
)
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
self.client.force_authenticate(user=superuser)
self.client.patch(
@@ -5357,7 +5358,7 @@ class TestDateWorkflowLocalization(
c = Correspondent.objects.create(name="Correspondent Name")
client = APIClient()
superuser = User.objects.create_superuser("superuser")
superuser = UserFactory(username="superuser", superuser=True)
client.force_authenticate(user=superuser)
trigger = WorkflowTrigger.objects.create(
@@ -2,22 +2,20 @@ import os
from unittest import mock
from django.conf import settings
from django.contrib.auth.models import User
from django.test import override_settings
from rest_framework import status
from rest_framework.test import APITestCase
from paperless.settings import _parse_remote_user_settings
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import UserFactory
class TestRemoteUser(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_superuser(
username="temp_admin",
)
self.user = UserFactory(username="temp_admin", superuser=True)
def test_remote_user(self) -> None:
"""
+6 -5
View File
@@ -15,6 +15,7 @@ from pytest_mock import MockerFixture
from rest_framework.authtoken.models import Token
from paperless.adapter import DrfTokenStrategy
from paperless_testing.factories import UserFactory
@pytest.mark.django_db
@@ -25,7 +26,7 @@ class TestCustomAccountAdapter:
# With no accounts, signups should be allowed
assert adapter.is_open_for_signup(None)
User.objects.create_user("testuser")
UserFactory(username="testuser")
settings.ACCOUNT_ALLOW_SIGNUPS = True
assert adapter.is_open_for_signup(None)
@@ -92,7 +93,7 @@ class TestCustomAccountAdapter:
) -> None:
settings.ACCOUNT_DEFAULT_GROUPS = ["group1", "group2"]
Group.objects.create(name="group1")
user = User.objects.create_user("testuser")
user = UserFactory(username="testuser")
adapter = get_adapter()
form = mocker.MagicMock(
cleaned_data={
@@ -152,7 +153,7 @@ class TestCustomSocialAccountAdapter:
settings.SOCIAL_ACCOUNT_DEFAULT_GROUPS = ["group1", "group2"]
Group.objects.create(name="group1")
adapter = get_social_adapter()
user = User.objects.create_user("testuser")
user = UserFactory(username="testuser")
sociallogin = mocker.MagicMock(user=user)
user = adapter.save_user(HttpRequest(), sociallogin, None)
@@ -187,7 +188,7 @@ class TestDrfTokenStrategy:
THEN:
- A new token is created and its key is returned
"""
user = User.objects.create_user("testuser")
user = UserFactory(username="testuser")
request = HttpRequest()
request.user = user
@@ -207,7 +208,7 @@ class TestDrfTokenStrategy:
THEN:
- The same token key is returned (no new token created)
"""
user = User.objects.create_user("testuser")
user = UserFactory(username="testuser")
existing_token = Token.objects.create(user=user)
request = HttpRequest()
+3 -5
View File
@@ -1,12 +1,13 @@
import uuid
from django.contrib.auth.models import User
from django.test import TestCase
from django.test import override_settings
from django.urls import resolve
from django.urls import reverse
from rest_framework import status
from paperless_testing.factories import UserFactory
class TestApiAuthViews(TestCase):
def test_api_auth_login_uses_allauth_login_view(self):
@@ -24,10 +25,7 @@ class TestApiAuthViews(TestCase):
@override_settings(DISABLE_REGULAR_LOGIN=True)
def test_api_auth_login_respects_disable_regular_login(self):
username = f"testuser-{uuid.uuid4().hex}"
User.objects.create_user(
username=username,
password="testpassword",
)
UserFactory(username=username, password="testpassword")
response = self.client.post(
reverse("rest_framework:login"),
+3 -3
View File
@@ -1,10 +1,10 @@
from django.contrib.auth.models import AnonymousUser
from django.contrib.auth.models import User
from django.test import RequestFactory
from django.test import TestCase
from django.test import override_settings
from paperless.auth import AutoLoginMiddleware
from paperless_testing.factories import UserFactory
@override_settings(AUTO_LOGIN_USERNAME="autologin")
@@ -29,7 +29,7 @@ class TestAutoLoginMiddleware(TestCase):
THEN:
- That user is attached to the request
"""
user = User.objects.create_user(username="autologin")
user = UserFactory(username="autologin")
request = self._process(self.factory.get("/"))
@@ -44,7 +44,7 @@ class TestAutoLoginMiddleware(TestCase):
THEN:
- The request is left anonymous rather than authenticated as them
"""
User.objects.create_user(username="autologin", is_active=False)
UserFactory(username="autologin", is_active=False)
request = self.factory.get("/")
request.user = AnonymousUser()
+23 -63
View File
@@ -1,7 +1,6 @@
from unittest.mock import Mock
from django.contrib.auth.models import Group
from django.contrib.auth.models import User
from django.http import HttpRequest
from django.test import TestCase
from django.test import override_settings
@@ -9,6 +8,7 @@ from django.test import override_settings
from documents.models import UiSettings
from paperless.signals import handle_failed_login
from paperless.signals import handle_social_account_updated
from paperless_testing.factories import UserFactory
class TestFailedLoginLogging(TestCase):
@@ -120,7 +120,7 @@ class TestSyncSocialLoginGroups(TestCase):
- The user's groups are updated to match the social login's groups
"""
group = Group.objects.create(name="group1")
user = User.objects.create_user(username="testuser")
user = UserFactory(username="testuser")
sociallogin = Mock(
user=user,
account=Mock(
@@ -147,7 +147,7 @@ class TestSyncSocialLoginGroups(TestCase):
- The user's groups are not updated
"""
Group.objects.create(name="group1")
user = User.objects.create_user(username="testuser")
user = UserFactory(username="testuser")
sociallogin = Mock(
user=user,
account=Mock(
@@ -180,7 +180,7 @@ class TestSyncSocialLoginGroups(TestCase):
would be rejected for a deactivated user anyway
"""
Group.objects.create(name="admin-group")
user = User.objects.create_user(
user = UserFactory(
username="inactive_user",
is_active=False,
is_superuser=False,
@@ -215,7 +215,7 @@ class TestSyncSocialLoginGroups(TestCase):
- The user's groups are cleared to match the social login's groups
"""
group = Group.objects.create(name="group1")
user = User.objects.create_user(username="testuser")
user = UserFactory(username="testuser")
user.groups.add(group)
user.save()
sociallogin = Mock(
@@ -244,7 +244,7 @@ class TestSyncSocialLoginGroups(TestCase):
- The user's groups are updated using `userinfo.groups`
"""
group = Group.objects.create(name="group1")
user = User.objects.create_user(username="testuser")
user = UserFactory(username="testuser")
sociallogin = Mock(
user=user,
account=Mock(
@@ -275,7 +275,7 @@ class TestSyncSocialLoginGroups(TestCase):
- The user's groups are updated using `id_token.groups`
"""
group = Group.objects.create(name="group1")
user = User.objects.create_user(username="testuser")
user = UserFactory(username="testuser")
sociallogin = Mock(
user=user,
account=Mock(
@@ -310,11 +310,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User is not promoted, since only an exact group match counts
"""
user = User.objects.create_user(
username="testuser",
is_superuser=False,
is_staff=False,
)
user = UserFactory(username="testuser", is_superuser=False, is_staff=False)
sociallogin = Mock(
user=user,
account=Mock(
@@ -345,11 +341,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User becomes superuser and staff
"""
user = User.objects.create_user(
username="testuser_s_e",
is_superuser=False,
is_staff=False,
)
user = UserFactory(username="testuser_s_e", is_superuser=False, is_staff=False)
sociallogin = Mock(
user=user,
account=Mock(
@@ -380,11 +372,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User loses superuser status but preserves staff status if they had it
"""
user = User.objects.create_user(
username="testuser_s_d",
is_superuser=True,
is_staff=True,
)
user = UserFactory(username="testuser_s_d", is_superuser=True, is_staff=True)
sociallogin = Mock(
user=user,
account=Mock(
@@ -415,11 +403,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User becomes staff
"""
user = User.objects.create_user(
username="testuser_st_e",
is_superuser=False,
is_staff=False,
)
user = UserFactory(username="testuser_st_e", is_superuser=False, is_staff=False)
sociallogin = Mock(
user=user,
account=Mock(
@@ -450,11 +434,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User loses staff status
"""
user = User.objects.create_user(
username="testuser_st_d",
is_superuser=False,
is_staff=True,
)
user = UserFactory(username="testuser_st_d", is_superuser=False, is_staff=True)
sociallogin = Mock(
user=user,
account=Mock(
@@ -485,11 +465,7 @@ class TestSyncSocialLoginGroups(TestCase):
- Roles are correctly assigned/revoked according to groups
"""
# Case 1: has both
user = User.objects.create_user(
username="testuser_b_1",
is_superuser=False,
is_staff=False,
)
user = UserFactory(username="testuser_b_1", is_superuser=False, is_staff=False)
sociallogin = Mock(
user=user,
account=Mock(extra_data={"groups": ["admin-group", "staff-group"]}),
@@ -504,11 +480,7 @@ class TestSyncSocialLoginGroups(TestCase):
self.assertTrue(user.is_staff)
# Case 2: has only staff
user2 = User.objects.create_user(
username="testuser_b_2",
is_superuser=True,
is_staff=True,
)
user2 = UserFactory(username="testuser_b_2", is_superuser=True, is_staff=True)
sociallogin2 = Mock(
user=user2,
account=Mock(extra_data={"groups": ["staff-group"]}),
@@ -523,11 +495,7 @@ class TestSyncSocialLoginGroups(TestCase):
self.assertTrue(user2.is_staff)
# Case 3: has neither
user3 = User.objects.create_user(
username="testuser_b_3",
is_superuser=True,
is_staff=True,
)
user3 = UserFactory(username="testuser_b_3", is_superuser=True, is_staff=True)
sociallogin3 = Mock(
user=user3,
account=Mock(extra_data={"groups": ["other-group"]}),
@@ -554,11 +522,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- Existing roles are not modified
"""
user = User.objects.create_user(
username="testuser_n_s",
is_superuser=True,
is_staff=True,
)
user = UserFactory(username="testuser_n_s", is_superuser=True, is_staff=True)
sociallogin = Mock(
user=user,
account=Mock(extra_data={"groups": ["admin-group", "staff-group"]}),
@@ -586,7 +550,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User's superuser status is demoted, matching the group claim exactly
"""
user = User.objects.create_user(
user = UserFactory(
username="local_admin",
password="password123",
is_superuser=True,
@@ -618,11 +582,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User's superuser status is demoted, even though they are the last admin
"""
user = User.objects.create_user(
username="last_admin",
is_superuser=True,
is_staff=True,
)
user = UserFactory(username="last_admin", is_superuser=True, is_staff=True)
user.set_unusable_password()
user.save()
@@ -652,7 +612,7 @@ class TestSyncSocialLoginGroups(TestCase):
THEN:
- User's staff status is demoted, matching the group claim exactly
"""
user = User.objects.create_user(
user = UserFactory(
username="local_staff",
password="password123",
is_superuser=False,
@@ -688,8 +648,8 @@ class TestUserGroupDeletionCleanup(TestCase):
THEN:
- References in ui_settings are cleaned up
"""
user = User.objects.create_user(username="testuser")
user2 = User.objects.create_user(username="testuser2")
user = UserFactory(username="testuser")
user2 = UserFactory(username="testuser2")
group = Group.objects.create(name="testgroup")
ui_settings = UiSettings.objects.create(
@@ -727,8 +687,8 @@ class TestUserGroupDeletionCleanup(TestCase):
THEN:
- Error is logged and the system remains stable
"""
user = User.objects.create_user(username="testuser")
user2 = User.objects.create_user(username="testuser2")
user = UserFactory(username="testuser")
user2 = UserFactory(username="testuser2")
user2_id = user2.id
Group.objects.create(name="testgroup")
+17 -16
View File
@@ -18,6 +18,7 @@ from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import CorrespondentFactory
from paperless_testing.factories import DocumentTypeFactory
from paperless_testing.factories import TagFactory
from paperless_testing.factories import UserFactory
class TestAPIMailAccounts(DirectoriesMixin, APITestCase):
@@ -33,7 +34,7 @@ class TestAPIMailAccounts(DirectoriesMixin, APITestCase):
super().setUp()
self.user = User.objects.create_user(username="temp_admin")
self.user = UserFactory(username="temp_admin")
self.user.user_permissions.add(*Permission.objects.all())
self.user.save()
self.client.force_authenticate(user=self.user)
@@ -291,7 +292,7 @@ class TestAPIMailAccounts(DirectoriesMixin, APITestCase):
imap_port=443,
owner=None,
)
user = User.objects.create_user(username="no_perms")
user = UserFactory(username="no_perms")
self.client.force_authenticate(user=user)
response = self.client.post(
@@ -321,7 +322,7 @@ class TestAPIMailAccounts(DirectoriesMixin, APITestCase):
THEN:
- API returns forbidden
"""
owner = User.objects.create_user(username="account_owner")
owner = UserFactory(username="account_owner")
account = MailAccountFactory(
username="admin",
password="secret",
@@ -329,7 +330,7 @@ class TestAPIMailAccounts(DirectoriesMixin, APITestCase):
imap_port=443,
owner=owner,
)
user = User.objects.create_user(username="object_perms_only")
user = UserFactory(username="object_perms_only")
assign_perm("change_mailaccount", user, account)
self.client.force_authenticate(user=user)
@@ -377,7 +378,7 @@ class TestAPIMailAccounts(DirectoriesMixin, APITestCase):
- Only unowned, owned by user or granted accounts are provided
"""
user2 = User.objects.create_user(username="temp_admin2")
user2 = UserFactory(username="temp_admin2")
account1 = MailAccountFactory(name="Email1")
account2 = MailAccountFactory(name="Email2", owner=self.user)
@@ -400,7 +401,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_user(username="temp_admin")
self.user = UserFactory(username="temp_admin")
self.user.user_permissions.add(*Permission.objects.all())
self.user.save()
self.client.force_authenticate(user=self.user)
@@ -590,7 +591,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
self.assertEqual(returned_rule1.action, MailRule.MailAction.DELETE)
def test_create_mail_rule_scopes_accounts(self) -> None:
other_user = User.objects.create_user(username="mail-owner")
other_user = UserFactory(username="mail-owner")
foreign_account = MailAccountFactory(name="ForeignEmail", owner=other_user)
response = self.client.post(
@@ -633,7 +634,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
def test_create_mail_rule_allowed_for_granted_account_change_permission(
self,
) -> None:
other_user = User.objects.create_user(username="mail-owner")
other_user = UserFactory(username="mail-owner")
foreign_account = MailAccountFactory(name="ForeignEmail", owner=other_user)
assign_perm("change_mailaccount", self.user, foreign_account)
@@ -658,7 +659,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
def test_update_mail_rule_forbidden_for_unpermitted_account(self) -> None:
own_account = MailAccountFactory()
other_user = User.objects.create_user(username="mail-owner")
other_user = UserFactory(username="mail-owner")
foreign_account = MailAccountFactory(owner=other_user)
rule1 = MailRuleFactory(account=own_account)
@@ -681,7 +682,7 @@ class TestAPIMailRules(DirectoriesMixin, APITestCase):
- Only unowned, owned by user or granted mail rules are provided
"""
user2 = User.objects.create_user(username="temp_admin2")
user2 = UserFactory(username="temp_admin2")
account1 = MailAccountFactory()
rule1 = MailRuleFactory(account=account1, order=0)
rule2 = MailRuleFactory(account=account1, order=1, owner=self.user)
@@ -737,7 +738,7 @@ class TestAPIProcessedMails(DirectoriesMixin, APITestCase):
def setUp(self) -> None:
super().setUp()
self.user = User.objects.create_user(username="temp_admin")
self.user = UserFactory(username="temp_admin")
self.user.user_permissions.add(*Permission.objects.all())
self.user.save()
self.client.force_authenticate(user=self.user)
@@ -751,7 +752,7 @@ class TestAPIProcessedMails(DirectoriesMixin, APITestCase):
THEN:
- Only unowned, owned by user or granted processed mails are provided
"""
user2 = User.objects.create_user(username="temp_admin2")
user2 = UserFactory(username="temp_admin2")
rule = MailRuleFactory()
pm1 = ProcessedMailFactory(rule=rule)
pm2 = ProcessedMailFactory(
@@ -802,7 +803,7 @@ class TestAPIProcessedMails(DirectoriesMixin, APITestCase):
THEN:
- Only the specified processed mails are deleted, respecting ownership and permissions
"""
user2 = User.objects.create_user(username="temp_admin2")
user2 = UserFactory(username="temp_admin2")
rule = MailRuleFactory()
# unowned, owned by self, and one with explicit object perm
pm_unowned = ProcessedMailFactory(rule=rule)
@@ -855,8 +856,8 @@ class TestAPIProcessedMails(DirectoriesMixin, APITestCase):
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_bulk_delete_requires_global_delete_permission(self) -> None:
owner = User.objects.create_user(username="mail_owner")
requester = User.objects.create_user(username="mail_deleter")
owner = UserFactory(username="mail_owner")
requester = UserFactory(username="mail_deleter")
requester.user_permissions.add(
Permission.objects.get(codename="add_processedmail"),
)
@@ -893,7 +894,7 @@ class TestAPIProcessedMails(DirectoriesMixin, APITestCase):
THEN:
- The request is rejected and neither mail is deleted
"""
user2 = User.objects.create_user(username="temp_admin2")
user2 = UserFactory(username="temp_admin2")
rule = MailRuleFactory()
# Created first so it sorts ahead of the forbidden mail, i.e. the
# permission check has to cover the whole batch before deleting rather
+7 -11
View File
@@ -9,7 +9,6 @@ from unittest import mock
import pytest
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.core.management import call_command
from django.db import DatabaseError
from django.test import TestCase
@@ -43,6 +42,7 @@ from paperless_mail.tests.factories import MailAccountFactory
from paperless_mail.tests.factories import MailRuleFactory
from paperless_testing.dirs import DirectoriesMixin
from paperless_testing.factories import CorrespondentFactory
from paperless_testing.factories import UserFactory
@dataclasses.dataclass
@@ -2263,10 +2263,7 @@ class TestMailAccountTestView(APITestCase):
self.mailMocker = MailMocker()
self.mailMocker.setUp()
self.addCleanup(self.mailMocker.doCleanups)
self.user = User.objects.create_user(
username="testuser",
password="testpassword",
)
self.user = UserFactory(username="testuser", password="testpassword")
self.user.user_permissions.add(
*Permission.objects.filter(
codename__in=["add_mailaccount", "change_mailaccount"],
@@ -2409,10 +2406,7 @@ class TestMailAccountTestView(APITestCase):
self.assertIn(expected_str, error_str)
def test_mail_account_test_view_existing_forbidden_for_other_owner(self) -> None:
other_user = User.objects.create_user(
username="otheruser",
password="testpassword",
)
other_user = UserFactory(username="otheruser", password="testpassword")
existing_account = MailAccount.objects.create(
name="Owned account",
imap_server="imap.example.com",
@@ -2535,9 +2529,10 @@ class TestMailAccountProcess(APITestCase):
self.mailMocker = MailMocker()
self.mailMocker.setUp()
self.addCleanup(self.mailMocker.doCleanups)
self.user = User.objects.create_superuser(
self.user = UserFactory(
username="testuser",
password="testpassword",
superuser=True,
)
self.client.force_authenticate(user=self.user)
self.account = MailAccount.objects.create(
@@ -2560,9 +2555,10 @@ class TestMailAccountProcess(APITestCase):
class TestMailRuleAPI(APITestCase):
def setUp(self) -> None:
self.user = User.objects.create_superuser(
self.user = UserFactory(
username="testuser",
password="testpassword",
superuser=True,
)
self.client.force_authenticate(user=self.user)
self.account = MailAccountFactory(owner=self.user)
+2 -2
View File
@@ -2,7 +2,6 @@ from datetime import timedelta
from unittest import mock
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.test import TestCase
from django.test import override_settings
from django.utils import timezone
@@ -14,6 +13,7 @@ from paperless_mail.mail import MailAccountHandler
from paperless_mail.models import MailAccount
from paperless_mail.oauth import PaperlessMailOAuth2Manager
from paperless_mail.tests.factories import MailAccountFactory
from paperless_testing.factories import UserFactory
@override_settings(
@@ -27,7 +27,7 @@ class TestMailOAuth(
TestCase,
):
def setUp(self) -> None:
self.user = User.objects.create_user("testuser")
self.user = UserFactory(username="testuser")
self.user.user_permissions.add(
*Permission.objects.filter(
codename__in=[
+4 -1
View File
@@ -78,7 +78,10 @@ class UserFactory(DjangoModelFactory[UserModelT]):
username = factory.Sequence(lambda n: f"user{n}")
is_staff = False
is_superuser = False
password = factory.django.Password("test")
# Hashing a real password costs about half a second per user, and no test
# authenticates with its password. None gives the unusable password
# create_user() gives.
password = factory.django.Password(None)
class Params:
superuser = factory.Trait(is_staff=True, is_superuser=True)