mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-09-14 13:47:58 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ac8dd7a04 | ||
|
|
f1b21628a9 |
@@ -2037,10 +2037,10 @@ class BulkEditSerializer(
|
|||||||
raise serializers.ValidationError("remove_custom_fields not specified")
|
raise serializers.ValidationError("remove_custom_fields not specified")
|
||||||
|
|
||||||
def _validate_owner(self, owner):
|
def _validate_owner(self, owner):
|
||||||
ownerUser = User.objects.get(pk=owner)
|
try:
|
||||||
if ownerUser is None:
|
return User.objects.get(pk=owner)
|
||||||
|
except (User.DoesNotExist, TypeError, ValueError):
|
||||||
raise serializers.ValidationError("Specified owner cannot be found")
|
raise serializers.ValidationError("Specified owner cannot be found")
|
||||||
return ownerUser
|
|
||||||
|
|
||||||
def _validate_parameters_set_permissions(self, parameters) -> None:
|
def _validate_parameters_set_permissions(self, parameters) -> None:
|
||||||
if "set_permissions" not in parameters:
|
if "set_permissions" not in parameters:
|
||||||
@@ -2060,7 +2060,7 @@ class BulkEditSerializer(
|
|||||||
or not float(parameters["degrees"]).is_integer()
|
or not float(parameters["degrees"]).is_integer()
|
||||||
):
|
):
|
||||||
raise serializers.ValidationError("invalid rotation degrees")
|
raise serializers.ValidationError("invalid rotation degrees")
|
||||||
except ValueError:
|
except (TypeError, ValueError):
|
||||||
raise serializers.ValidationError("invalid rotation degrees")
|
raise serializers.ValidationError("invalid rotation degrees")
|
||||||
|
|
||||||
def _validate_source_mode(self, parameters) -> None:
|
def _validate_source_mode(self, parameters) -> None:
|
||||||
@@ -2073,6 +2073,8 @@ class BulkEditSerializer(
|
|||||||
def _validate_parameters_split(self, parameters) -> None:
|
def _validate_parameters_split(self, parameters) -> None:
|
||||||
if "pages" not in parameters:
|
if "pages" not in parameters:
|
||||||
raise serializers.ValidationError("pages not specified")
|
raise serializers.ValidationError("pages not specified")
|
||||||
|
if not isinstance(parameters["pages"], str):
|
||||||
|
raise serializers.ValidationError("invalid pages specified")
|
||||||
try:
|
try:
|
||||||
pages = []
|
pages = []
|
||||||
docs = parameters["pages"].split(",")
|
docs = parameters["pages"].split(",")
|
||||||
|
|||||||
@@ -1165,6 +1165,65 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
|
|||||||
self.assertIn(b"set_permissions not specified", response.content)
|
self.assertIn(b"set_permissions not specified", response.content)
|
||||||
m.assert_not_called()
|
m.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch("documents.serialisers.bulk_edit.set_permissions")
|
||||||
|
def test_set_permissions_rejects_nonexistent_owner(self, m) -> None:
|
||||||
|
"""
|
||||||
|
BulkEditSerializer._validate_owner called User.objects.get(pk=owner)
|
||||||
|
with no try/except, so a syntactically valid but nonexistent user
|
||||||
|
id raised an uncaught User.DoesNotExist instead of a clean 400.
|
||||||
|
"""
|
||||||
|
self.setup_mock(m, "set_permissions")
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
"/api/documents/bulk_edit/",
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"documents": [self.doc2.id],
|
||||||
|
"method": "set_permissions",
|
||||||
|
"parameters": {
|
||||||
|
"set_permissions": {"view": {"users": [self.user.id]}},
|
||||||
|
"owner": 999999,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
content_type="application/json",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
m.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch("documents.serialisers.bulk_edit.set_permissions")
|
||||||
|
def test_set_permissions_rejects_wrong_typed_owner(self, m) -> None:
|
||||||
|
"""
|
||||||
|
_validate_owner only caught User.DoesNotExist -- a wrong-typed
|
||||||
|
owner (list/dict/non-numeric string) reaches
|
||||||
|
User.objects.get(pk=owner) and raises an uncaught TypeError or
|
||||||
|
ValueError instead, since `parameters` is a bare DictField with
|
||||||
|
no type checking on "owner" at that level.
|
||||||
|
"""
|
||||||
|
self.setup_mock(m, "set_permissions")
|
||||||
|
|
||||||
|
for bad_owner in (["not", "an", "id"], {"nested": "dict"}, "not-a-number"):
|
||||||
|
with self.subTest(owner=bad_owner):
|
||||||
|
response = self.client.post(
|
||||||
|
"/api/documents/bulk_edit/",
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"documents": [self.doc2.id],
|
||||||
|
"method": "set_permissions",
|
||||||
|
"parameters": {
|
||||||
|
"set_permissions": {
|
||||||
|
"view": {"users": [self.user.id]},
|
||||||
|
},
|
||||||
|
"owner": bad_owner,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
content_type="application/json",
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
m.assert_not_called()
|
||||||
|
|
||||||
@mock.patch("documents.serialisers.bulk_edit.set_permissions")
|
@mock.patch("documents.serialisers.bulk_edit.set_permissions")
|
||||||
def test_set_permissions_merge(self, m) -> None:
|
def test_set_permissions_merge(self, m) -> None:
|
||||||
self.setup_mock(m, "set_permissions")
|
self.setup_mock(m, "set_permissions")
|
||||||
@@ -1438,6 +1497,53 @@ class TestBulkEditAPI(DirectoriesMixin, APITestCase):
|
|||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
m.assert_not_called()
|
m.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch("documents.serialisers.bulk_edit.rotate")
|
||||||
|
def test_bulk_edit_rotate_rejects_null_degrees(self, m) -> None:
|
||||||
|
"""
|
||||||
|
BulkEditSerializer._validate_parameters_rotate's
|
||||||
|
`float(parameters["degrees"])` raised an uncaught TypeError for
|
||||||
|
None (only ValueError was caught), reachable via the legacy
|
||||||
|
generic /api/documents/bulk_edit/ method="rotate" path (the
|
||||||
|
dedicated /api/documents/rotate/ endpoint isn't affected, its
|
||||||
|
`degrees` field is a typed IntegerField).
|
||||||
|
"""
|
||||||
|
self.setup_mock(m, "rotate")
|
||||||
|
response = self.client.post(
|
||||||
|
"/api/documents/bulk_edit/",
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"documents": [self.doc2.id],
|
||||||
|
"method": "rotate",
|
||||||
|
"parameters": {"degrees": None},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
content_type="application/json",
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
m.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch("documents.serialisers.bulk_edit.split")
|
||||||
|
def test_bulk_edit_split_rejects_null_pages(self, m) -> None:
|
||||||
|
"""
|
||||||
|
BulkEditSerializer._validate_parameters_split called
|
||||||
|
parameters["pages"].split(",") with no type check, so a null
|
||||||
|
value raised an uncaught AttributeError instead of a clean 400.
|
||||||
|
"""
|
||||||
|
self.setup_mock(m, "split")
|
||||||
|
response = self.client.post(
|
||||||
|
"/api/documents/bulk_edit/",
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"documents": [self.doc2.id],
|
||||||
|
"method": "split",
|
||||||
|
"parameters": {"pages": None},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
content_type="application/json",
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
m.assert_not_called()
|
||||||
|
|
||||||
@mock.patch("documents.views.bulk_edit.rotate")
|
@mock.patch("documents.views.bulk_edit.rotate")
|
||||||
def test_rotate_insufficient_permissions(self, m) -> None:
|
def test_rotate_insufficient_permissions(self, m) -> None:
|
||||||
self.doc1.owner = User.objects.get(username="temp_admin")
|
self.doc1.owner = User.objects.get(username="temp_admin")
|
||||||
|
|||||||
Reference in New Issue
Block a user