mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-08-18 00:46:25 +00:00
Feature: custom fields filtering & bulk editing (#6484)
This commit is contained in:
@@ -7,6 +7,7 @@ from rest_framework import status
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from documents.models import Correspondent
|
||||
from documents.models import CustomField
|
||||
from documents.models import Document
|
||||
from documents.models import DocumentType
|
||||
from documents.models import StoragePath
|
||||
@@ -49,6 +50,8 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
|
||||
self.doc3.tags.add(self.t2)
|
||||
self.doc4.tags.add(self.t1, self.t2)
|
||||
self.sp1 = StoragePath.objects.create(name="sp1", path="Something/{checksum}")
|
||||
self.cf1 = CustomField.objects.create(name="cf1", data_type="text")
|
||||
self.cf2 = CustomField.objects.create(name="cf2", data_type="text")
|
||||
|
||||
@mock.patch("documents.serialisers.bulk_edit.set_correspondent")
|
||||
def test_api_set_correspondent(self, m):
|
||||
@@ -222,6 +225,135 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
m.assert_not_called()
|
||||
|
||||
@mock.patch("documents.serialisers.bulk_edit.modify_custom_fields")
|
||||
def test_api_modify_custom_fields(self, m):
|
||||
m.return_value = "OK"
|
||||
response = self.client.post(
|
||||
"/api/documents/bulk_edit/",
|
||||
json.dumps(
|
||||
{
|
||||
"documents": [self.doc1.id, self.doc3.id],
|
||||
"method": "modify_custom_fields",
|
||||
"parameters": {
|
||||
"add_custom_fields": [self.cf1.id],
|
||||
"remove_custom_fields": [self.cf2.id],
|
||||
},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
m.assert_called_once()
|
||||
args, kwargs = m.call_args
|
||||
self.assertListEqual(args[0], [self.doc1.id, self.doc3.id])
|
||||
self.assertEqual(kwargs["add_custom_fields"], [self.cf1.id])
|
||||
self.assertEqual(kwargs["remove_custom_fields"], [self.cf2.id])
|
||||
|
||||
@mock.patch("documents.serialisers.bulk_edit.modify_custom_fields")
|
||||
def test_api_modify_custom_fields_invalid_params(self, m):
|
||||
"""
|
||||
GIVEN:
|
||||
- API data to modify custom fields is malformed
|
||||
WHEN:
|
||||
- API to edit custom fields is called
|
||||
THEN:
|
||||
- API returns HTTP 400
|
||||
- modify_custom_fields is not called
|
||||
"""
|
||||
m.return_value = "OK"
|
||||
|
||||
# Missing add_custom_fields
|
||||
response = self.client.post(
|
||||
"/api/documents/bulk_edit/",
|
||||
json.dumps(
|
||||
{
|
||||
"documents": [self.doc1.id, self.doc3.id],
|
||||
"method": "modify_custom_fields",
|
||||
"parameters": {
|
||||
"add_custom_fields": [self.cf1.id],
|
||||
},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
m.assert_not_called()
|
||||
|
||||
# Missing remove_custom_fields
|
||||
response = self.client.post(
|
||||
"/api/documents/bulk_edit/",
|
||||
json.dumps(
|
||||
{
|
||||
"documents": [self.doc1.id, self.doc3.id],
|
||||
"method": "modify_custom_fields",
|
||||
"parameters": {
|
||||
"remove_custom_fields": [self.cf1.id],
|
||||
},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
m.assert_not_called()
|
||||
|
||||
# Not a list
|
||||
response = self.client.post(
|
||||
"/api/documents/bulk_edit/",
|
||||
json.dumps(
|
||||
{
|
||||
"documents": [self.doc1.id, self.doc3.id],
|
||||
"method": "modify_custom_fields",
|
||||
"parameters": {
|
||||
"add_custom_fields": self.cf1.id,
|
||||
"remove_custom_fields": self.cf2.id,
|
||||
},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
m.assert_not_called()
|
||||
|
||||
# Not a list of integers
|
||||
|
||||
# Missing remove_custom_fields
|
||||
response = self.client.post(
|
||||
"/api/documents/bulk_edit/",
|
||||
json.dumps(
|
||||
{
|
||||
"documents": [self.doc1.id, self.doc3.id],
|
||||
"method": "modify_custom_fields",
|
||||
"parameters": {
|
||||
"add_custom_fields": ["foo"],
|
||||
"remove_custom_fields": ["bar"],
|
||||
},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
m.assert_not_called()
|
||||
|
||||
# Custom field ID not found
|
||||
|
||||
# Missing remove_custom_fields
|
||||
response = self.client.post(
|
||||
"/api/documents/bulk_edit/",
|
||||
json.dumps(
|
||||
{
|
||||
"documents": [self.doc1.id, self.doc3.id],
|
||||
"method": "modify_custom_fields",
|
||||
"parameters": {
|
||||
"add_custom_fields": [self.cf1.id],
|
||||
"remove_custom_fields": [99],
|
||||
},
|
||||
},
|
||||
),
|
||||
content_type="application/json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
m.assert_not_called()
|
||||
|
||||
@mock.patch("documents.serialisers.bulk_edit.delete")
|
||||
def test_api_delete(self, m):
|
||||
m.return_value = "OK"
|
||||
|
@@ -920,6 +920,34 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
|
||||
),
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
d4.id,
|
||||
search_query(
|
||||
"&has_custom_fields=1",
|
||||
),
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
d4.id,
|
||||
search_query(
|
||||
"&custom_fields__id__in=" + str(cf1.id),
|
||||
),
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
d4.id,
|
||||
search_query(
|
||||
"&custom_fields__id__all=" + str(cf1.id),
|
||||
),
|
||||
)
|
||||
|
||||
self.assertNotIn(
|
||||
d4.id,
|
||||
search_query(
|
||||
"&custom_fields__id__none=" + str(cf1.id),
|
||||
),
|
||||
)
|
||||
|
||||
def test_search_filtering_respect_owner(self):
|
||||
"""
|
||||
GIVEN:
|
||||
|
@@ -11,6 +11,8 @@ from guardian.shortcuts import get_users_with_perms
|
||||
|
||||
from documents import bulk_edit
|
||||
from documents.models import Correspondent
|
||||
from documents.models import CustomField
|
||||
from documents.models import CustomFieldInstance
|
||||
from documents.models import Document
|
||||
from documents.models import DocumentType
|
||||
from documents.models import StoragePath
|
||||
@@ -186,6 +188,53 @@ class TestBulkEdit(DirectoriesMixin, TestCase):
|
||||
# TODO: doc3 should not be affected, but the query for that is rather complicated
|
||||
self.assertCountEqual(kwargs["document_ids"], [self.doc2.id, self.doc3.id])
|
||||
|
||||
def test_modify_custom_fields(self):
|
||||
cf = CustomField.objects.create(
|
||||
name="cf1",
|
||||
data_type=CustomField.FieldDataType.STRING,
|
||||
)
|
||||
cf2 = CustomField.objects.create(
|
||||
name="cf2",
|
||||
data_type=CustomField.FieldDataType.INT,
|
||||
)
|
||||
cf3 = CustomField.objects.create(
|
||||
name="cf3",
|
||||
data_type=CustomField.FieldDataType.STRING,
|
||||
)
|
||||
CustomFieldInstance.objects.create(
|
||||
document=self.doc1,
|
||||
field=cf,
|
||||
)
|
||||
CustomFieldInstance.objects.create(
|
||||
document=self.doc2,
|
||||
field=cf,
|
||||
)
|
||||
CustomFieldInstance.objects.create(
|
||||
document=self.doc2,
|
||||
field=cf3,
|
||||
)
|
||||
bulk_edit.modify_custom_fields(
|
||||
[self.doc1.id, self.doc2.id],
|
||||
add_custom_fields=[cf2.id],
|
||||
remove_custom_fields=[cf.id],
|
||||
)
|
||||
|
||||
self.doc1.refresh_from_db()
|
||||
self.doc2.refresh_from_db()
|
||||
|
||||
self.assertEqual(
|
||||
self.doc1.custom_fields.count(),
|
||||
1,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.doc2.custom_fields.count(),
|
||||
2,
|
||||
)
|
||||
|
||||
self.async_task.assert_called_once()
|
||||
args, kwargs = self.async_task.call_args
|
||||
self.assertCountEqual(kwargs["document_ids"], [self.doc1.id, self.doc2.id])
|
||||
|
||||
def test_delete(self):
|
||||
self.assertEqual(Document.objects.count(), 5)
|
||||
bulk_edit.delete([self.doc1.id, self.doc2.id])
|
||||
|
Reference in New Issue
Block a user