mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-04-21 23:39:28 +00:00
Backend update only version label
This commit is contained in:
@@ -2080,6 +2080,22 @@ class DocumentVersionSerializer(serializers.Serializer):
|
||||
validate_document = PostDocumentSerializer().validate_document
|
||||
|
||||
|
||||
class DocumentVersionLabelSerializer(serializers.Serializer):
|
||||
version_label = serializers.CharField(
|
||||
label="Version label",
|
||||
required=True,
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
max_length=64,
|
||||
)
|
||||
|
||||
def validate_version_label(self, value):
|
||||
if value is None:
|
||||
return None
|
||||
normalized = value.strip()
|
||||
return normalized or None
|
||||
|
||||
|
||||
class BulkDownloadSerializer(DocumentListSerializer):
|
||||
content = serializers.ChoiceField(
|
||||
choices=["archive", "originals", "both"],
|
||||
|
||||
@@ -325,6 +325,107 @@ class TestDocumentVersioningApi(DirectoriesMixin, APITestCase):
|
||||
|
||||
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_update_version_label_updates_and_trims(self) -> None:
|
||||
root = Document.objects.create(
|
||||
title="root",
|
||||
checksum="root",
|
||||
mime_type="application/pdf",
|
||||
)
|
||||
version = Document.objects.create(
|
||||
title="v1",
|
||||
checksum="v1",
|
||||
mime_type="application/pdf",
|
||||
root_document=root,
|
||||
version_label="old",
|
||||
)
|
||||
|
||||
resp = self.client.patch(
|
||||
f"/api/documents/{root.id}/versions/{version.id}/",
|
||||
{"version_label": " Label 1 "},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
version.refresh_from_db()
|
||||
self.assertEqual(version.version_label, "Label 1")
|
||||
self.assertEqual(resp.data["version_label"], "Label 1")
|
||||
self.assertEqual(resp.data["id"], version.id)
|
||||
self.assertFalse(resp.data["is_root"])
|
||||
|
||||
def test_update_version_label_clears_on_blank(self) -> None:
|
||||
root = Document.objects.create(
|
||||
title="root",
|
||||
checksum="root",
|
||||
mime_type="application/pdf",
|
||||
version_label="Root Label",
|
||||
)
|
||||
|
||||
resp = self.client.patch(
|
||||
f"/api/documents/{root.id}/versions/{root.id}/",
|
||||
{"version_label": " "},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(resp.status_code, status.HTTP_200_OK)
|
||||
root.refresh_from_db()
|
||||
self.assertIsNone(root.version_label)
|
||||
self.assertIsNone(resp.data["version_label"])
|
||||
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")
|
||||
other.user_permissions.add(
|
||||
Permission.objects.get(codename="change_document"),
|
||||
)
|
||||
root = Document.objects.create(
|
||||
title="root",
|
||||
checksum="root",
|
||||
mime_type="application/pdf",
|
||||
owner=owner,
|
||||
)
|
||||
version = Document.objects.create(
|
||||
title="v1",
|
||||
checksum="v1",
|
||||
mime_type="application/pdf",
|
||||
root_document=root,
|
||||
)
|
||||
self.client.force_authenticate(user=other)
|
||||
|
||||
resp = self.client.patch(
|
||||
f"/api/documents/{root.id}/versions/{version.id}/",
|
||||
{"version_label": "Blocked"},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(resp.status_code, status.HTTP_403_FORBIDDEN)
|
||||
|
||||
def test_update_version_label_returns_404_for_unrelated_version(self) -> None:
|
||||
root = Document.objects.create(
|
||||
title="root",
|
||||
checksum="root",
|
||||
mime_type="application/pdf",
|
||||
)
|
||||
other_root = Document.objects.create(
|
||||
title="other",
|
||||
checksum="other",
|
||||
mime_type="application/pdf",
|
||||
)
|
||||
other_version = Document.objects.create(
|
||||
title="other-v1",
|
||||
checksum="other-v1",
|
||||
mime_type="application/pdf",
|
||||
root_document=other_root,
|
||||
)
|
||||
|
||||
resp = self.client.patch(
|
||||
f"/api/documents/{root.id}/versions/{other_version.id}/",
|
||||
{"version_label": "Nope"},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(resp.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_download_version_param_errors(self) -> None:
|
||||
root = self._create_pdf(title="root", checksum="root")
|
||||
|
||||
|
||||
@@ -178,6 +178,7 @@ from documents.serialisers import CustomFieldSerializer
|
||||
from documents.serialisers import DocumentListSerializer
|
||||
from documents.serialisers import DocumentSerializer
|
||||
from documents.serialisers import DocumentTypeSerializer
|
||||
from documents.serialisers import DocumentVersionLabelSerializer
|
||||
from documents.serialisers import DocumentVersionSerializer
|
||||
from documents.serialisers import EmailSerializer
|
||||
from documents.serialisers import NotesSerializer
|
||||
@@ -1663,6 +1664,31 @@ class DocumentViewSet(
|
||||
"Error updating document, check logs for more detail.",
|
||||
)
|
||||
|
||||
def _get_root_doc_for_version_action(self, pk) -> Document:
|
||||
try:
|
||||
root_doc = Document.objects.select_related(
|
||||
"owner",
|
||||
"root_document",
|
||||
).get(pk=pk)
|
||||
except Document.DoesNotExist:
|
||||
raise Http404
|
||||
return get_root_document(root_doc)
|
||||
|
||||
def _get_version_doc_for_root(self, root_doc: Document, version_id) -> Document:
|
||||
try:
|
||||
version_doc = Document.objects.select_related("owner").get(
|
||||
pk=version_id,
|
||||
)
|
||||
except Document.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
if (
|
||||
version_doc.id != root_doc.id
|
||||
and version_doc.root_document_id != root_doc.id
|
||||
):
|
||||
raise Http404
|
||||
return version_doc
|
||||
|
||||
@extend_schema(
|
||||
operation_id="documents_delete_version",
|
||||
parameters=[
|
||||
@@ -1686,14 +1712,7 @@ class DocumentViewSet(
|
||||
url_path=r"versions/(?P<version_id>\d+)",
|
||||
)
|
||||
def delete_version(self, request, pk=None, version_id=None):
|
||||
try:
|
||||
root_doc = Document.objects.select_related(
|
||||
"owner",
|
||||
"root_document",
|
||||
).get(pk=pk)
|
||||
root_doc = get_root_document(root_doc)
|
||||
except Document.DoesNotExist:
|
||||
raise Http404
|
||||
root_doc = self._get_root_doc_for_version_action(pk)
|
||||
|
||||
if request.user is not None and not has_perms_owner_aware(
|
||||
request.user,
|
||||
@@ -1702,21 +1721,13 @@ class DocumentViewSet(
|
||||
):
|
||||
return HttpResponseForbidden("Insufficient permissions")
|
||||
|
||||
try:
|
||||
version_doc = Document.objects.select_related("owner").get(
|
||||
pk=version_id,
|
||||
)
|
||||
except Document.DoesNotExist:
|
||||
raise Http404
|
||||
version_doc = self._get_version_doc_for_root(root_doc, version_id)
|
||||
|
||||
if version_doc.id == root_doc.id:
|
||||
return HttpResponseBadRequest(
|
||||
"Cannot delete the root/original version. Delete the document instead.",
|
||||
)
|
||||
|
||||
if version_doc.root_document_id != root_doc.id:
|
||||
raise Http404
|
||||
|
||||
from documents import index
|
||||
|
||||
index.remove_document_from_index(version_doc)
|
||||
@@ -1752,6 +1763,78 @@ class DocumentViewSet(
|
||||
},
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
operation_id="documents_update_version_label",
|
||||
request=DocumentVersionLabelSerializer,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="version_id",
|
||||
type=OpenApiTypes.INT,
|
||||
location=OpenApiParameter.PATH,
|
||||
),
|
||||
],
|
||||
responses=inline_serializer(
|
||||
name="UpdateDocumentVersionLabelResult",
|
||||
fields={
|
||||
"id": serializers.IntegerField(),
|
||||
"added": serializers.DateTimeField(),
|
||||
"version_label": serializers.CharField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
),
|
||||
"checksum": serializers.CharField(
|
||||
required=False,
|
||||
allow_null=True,
|
||||
),
|
||||
"is_root": serializers.BooleanField(),
|
||||
},
|
||||
),
|
||||
)
|
||||
@delete_version.mapping.patch
|
||||
def update_version_label(self, request, pk=None, version_id=None):
|
||||
serializer = DocumentVersionLabelSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
root_doc = self._get_root_doc_for_version_action(pk)
|
||||
if request.user is not None and not has_perms_owner_aware(
|
||||
request.user,
|
||||
"change_document",
|
||||
root_doc,
|
||||
):
|
||||
return HttpResponseForbidden("Insufficient permissions")
|
||||
|
||||
version_doc = self._get_version_doc_for_root(root_doc, version_id)
|
||||
old_label = version_doc.version_label
|
||||
version_doc.version_label = serializer.validated_data["version_label"]
|
||||
version_doc.save(update_fields=["version_label"])
|
||||
|
||||
if settings.AUDIT_LOG_ENABLED and old_label != version_doc.version_label:
|
||||
actor = (
|
||||
request.user if request.user and request.user.is_authenticated else None
|
||||
)
|
||||
LogEntry.objects.log_create(
|
||||
instance=root_doc,
|
||||
changes={
|
||||
"Version Label": [old_label, version_doc.version_label],
|
||||
},
|
||||
action=LogEntry.Action.UPDATE,
|
||||
actor=actor,
|
||||
additional_data={
|
||||
"reason": "Version label updated",
|
||||
"version_id": version_doc.id,
|
||||
},
|
||||
)
|
||||
|
||||
return Response(
|
||||
{
|
||||
"id": version_doc.id,
|
||||
"added": version_doc.added,
|
||||
"version_label": version_doc.version_label,
|
||||
"checksum": version_doc.checksum,
|
||||
"is_root": version_doc.id == root_doc.id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ChatStreamingSerializer(serializers.Serializer):
|
||||
q = serializers.CharField(required=True)
|
||||
|
||||
Reference in New Issue
Block a user