mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-11-03 13:35:37 +00:00
Enhancement: duplicates filter (#13994)
This commit is contained in:
1 parent
05905287b3
commit
9a47b20d2a
11 files changed
+459
-4
No files matched your search
@@ -717,6 +717,44 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
|
||||
self.assertEqual(args[0], [self.doc2.id])
|
||||
self.assertEqual(kwargs["storage_path"], self.sp1.id)
|
||||
|
||||
@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.user_permissions.add(
|
||||
Permission.objects.get(codename="change_document"),
|
||||
)
|
||||
first_duplicate = Document.objects.create(
|
||||
checksum="owned-duplicate",
|
||||
title="First duplicate",
|
||||
owner=user,
|
||||
)
|
||||
second_duplicate = Document.objects.create(
|
||||
checksum="owned-duplicate",
|
||||
title="Second duplicate",
|
||||
owner=user,
|
||||
)
|
||||
self.client.force_authenticate(user=user)
|
||||
|
||||
response = self.client.post(
|
||||
"/api/documents/bulk_edit/",
|
||||
json.dumps(
|
||||
{
|
||||
"all": True,
|
||||
"filters": {"has_duplicates": True},
|
||||
"method": "set_storage_path",
|
||||
"parameters": {"storage_path": self.sp1.id},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
m.assert_called_once()
|
||||
args, kwargs = m.call_args
|
||||
self.assertCountEqual(args[0], [first_duplicate.id, second_duplicate.id])
|
||||
self.assertEqual(kwargs["storage_path"], self.sp1.id)
|
||||
|
||||
@mock.patch("documents.search.get_backend")
|
||||
@mock.patch("documents.serialisers.bulk_edit.set_storage_path")
|
||||
def test_api_bulk_edit_with_all_true_resolves_documents_from_search_filters(
|
||||
|
||||
@@ -981,6 +981,128 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0]["id"], doc.id)
|
||||
|
||||
def test_has_duplicates_filter(self) -> None:
|
||||
original_match = Document.objects.create(
|
||||
title="original match",
|
||||
checksum="same-original",
|
||||
)
|
||||
second_original_match = Document.objects.create(
|
||||
title="second original match",
|
||||
checksum="same-original",
|
||||
)
|
||||
archive_match = Document.objects.create(
|
||||
title="archive match",
|
||||
checksum="archive-source",
|
||||
archive_checksum="same-archive",
|
||||
)
|
||||
original_to_archive_match = Document.objects.create(
|
||||
title="original to archive match",
|
||||
checksum="same-archive",
|
||||
)
|
||||
first_archive_match = Document.objects.create(
|
||||
title="first archive match",
|
||||
checksum="first-archive-source",
|
||||
archive_checksum="same-archive-only",
|
||||
)
|
||||
second_archive_match = Document.objects.create(
|
||||
title="second archive match",
|
||||
checksum="second-archive-source",
|
||||
archive_checksum="same-archive-only",
|
||||
)
|
||||
first_empty_archive = Document.objects.create(
|
||||
title="first empty archive",
|
||||
checksum="first-empty-archive",
|
||||
archive_checksum="",
|
||||
)
|
||||
second_empty_archive = Document.objects.create(
|
||||
title="second empty archive",
|
||||
checksum="second-empty-archive",
|
||||
archive_checksum="",
|
||||
)
|
||||
unique = Document.objects.create(title="unique", checksum="unique")
|
||||
version_root = Document.objects.create(
|
||||
title="version root",
|
||||
checksum="version-root",
|
||||
)
|
||||
Document.objects.create(
|
||||
title="version",
|
||||
checksum=unique.checksum,
|
||||
root_document=version_root,
|
||||
version_index=1,
|
||||
)
|
||||
trash_match = Document.objects.create(
|
||||
title="trash match",
|
||||
checksum="trash-match",
|
||||
)
|
||||
trashed_duplicate = Document.objects.create(
|
||||
title="trashed duplicate",
|
||||
checksum="trash-match",
|
||||
)
|
||||
trashed_duplicate.delete()
|
||||
|
||||
response = self.client.get("/api/documents/?has_duplicates=true")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertCountEqual(
|
||||
[document["id"] for document in response.data["results"]],
|
||||
[
|
||||
original_match.id,
|
||||
second_original_match.id,
|
||||
archive_match.id,
|
||||
original_to_archive_match.id,
|
||||
first_archive_match.id,
|
||||
second_archive_match.id,
|
||||
trash_match.id,
|
||||
],
|
||||
)
|
||||
|
||||
response = self.client.get("/api/documents/?has_duplicates=false")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertCountEqual(
|
||||
[document["id"] for document in response.data["results"]],
|
||||
[
|
||||
unique.id,
|
||||
version_root.id,
|
||||
first_empty_archive.id,
|
||||
second_empty_archive.id,
|
||||
],
|
||||
)
|
||||
|
||||
response = self.client.get(f"/api/documents/{first_empty_archive.id}/")
|
||||
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")
|
||||
requester.user_permissions.add(
|
||||
Permission.objects.get(codename="view_document"),
|
||||
)
|
||||
visible_document = Document.objects.create(
|
||||
title="visible document",
|
||||
checksum="permission-match",
|
||||
owner=requester,
|
||||
)
|
||||
hidden_duplicate = Document.objects.create(
|
||||
title="hidden duplicate",
|
||||
checksum="permission-match",
|
||||
owner=owner,
|
||||
)
|
||||
self.client.force_authenticate(user=requester)
|
||||
|
||||
response = self.client.get("/api/documents/?has_duplicates=true")
|
||||
self.assertNotIn(
|
||||
visible_document.id,
|
||||
[document["id"] for document in response.data["results"]],
|
||||
)
|
||||
|
||||
assign_perm("view_document", requester, hidden_duplicate)
|
||||
response = self.client.get("/api/documents/?has_duplicates=true")
|
||||
self.assertIn(
|
||||
visible_document.id,
|
||||
[document["id"] for document in response.data["results"]],
|
||||
)
|
||||
|
||||
def test_custom_fields_icontains_filter_no_duplicates(self) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
|
||||
Reference in new issue
Block a user