Compare commits

...
5 changed files with 122 additions and 13 deletions

No files matched your search

+8
View File
@@ -1381,9 +1381,17 @@ def task_revoked_handler(
return
try:
close_old_connections()
reason = "Task revoked before completion."
if expired:
reason = "Task expired before execution."
elif terminated:
reason = "Task terminated during execution."
PaperlessTask.objects.filter(task_id=task_id).update(
status=PaperlessTask.Status.REVOKED,
date_done=timezone.now(),
result_data={
"reason": (reason + " Check worker logs for details."),
},
)
except Exception: # pragma: no cover
logger.exception("Updating PaperlessTask on revocation failed")
+65
View File
@@ -46,6 +46,7 @@ from documents.models import UiSettings
from documents.models import Workflow
from documents.models import WorkflowAction
from documents.models import WorkflowTrigger
from documents.search import get_backend
from documents.signals.handlers import run_workflows
from documents.tests.utils import ConsumeTaskMixin
from paperless_testing.dirs import DirectoriesMixin
@@ -66,6 +67,70 @@ class TestDocumentApi(DirectoriesMixin, ConsumeTaskMixin, APITestCase):
self.client.force_authenticate(user=self.user)
cache.clear()
def test_detail_save_indexes_final_workflow_state(self) -> None:
viewer = UserFactory()
grant_global(viewer, "view_document")
inbox = TagFactory(is_inbox_tag=True)
doc = DocumentFactory(owner=self.user, content="distinctiveword")
doc.tags.add(inbox)
trigger = WorkflowTrigger.objects.create(
type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED,
)
action = WorkflowAction.objects.create(assign_title="Workflow title")
action.assign_view_users.add(viewer)
action.remove_view_users.add(viewer)
workflow = Workflow.objects.create(name="Update document")
workflow.triggers.add(trigger)
workflow.actions.add(action)
backend = get_backend()
backend.add_or_update(doc)
for action_type in (
WorkflowAction.WorkflowActionType.ASSIGNMENT,
WorkflowAction.WorkflowActionType.REMOVAL,
WorkflowAction.WorkflowActionType.MOVE_TO_TRASH,
):
with self.subTest(action_type=action_type):
grant = action_type == WorkflowAction.WorkflowActionType.ASSIGNMENT
action.type = action_type
action.save()
trigger.filter_has_not_tags.set([inbox] if grant else [])
trigger.filter_has_tags.set([] if grant else [inbox])
self.client.force_authenticate(self.user)
response = self.client.patch(
f"/api/documents/{doc.pk}/",
{"tags": [] if grant else [inbox.pk]},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.client.force_authenticate(viewer)
self.assertEqual(
self.client.get(f"/api/documents/{doc.pk}/").status_code,
status.HTTP_200_OK if grant else status.HTTP_404_NOT_FOUND,
)
# Check the index directly: the API's DB permission filtering
# would otherwise hide stale grants and trashed index entries.
self.assertEqual(
list(backend.search_ids("distinctiveword", user=viewer)),
[doc.pk] if grant else [],
)
if grant:
response = self.client.get(
"/api/documents/",
{"query": "distinctiveword AND title:workflow"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
[result["id"] for result in response.data["results"]],
[doc.pk],
)
elif action_type == WorkflowAction.WorkflowActionType.MOVE_TO_TRASH:
self.assertFalse(Document.objects.filter(pk=doc.pk).exists())
self.assertEqual(
list(backend.search_ids("distinctiveword", user=None)),
[],
)
def testDocuments(self) -> None:
response = self.client.get("/api/documents/").data
+30
View File
@@ -429,6 +429,36 @@ class TestTaskRevokedHandler:
assert task.status == PaperlessTask.Status.REVOKED
assert task.date_done is not None
@pytest.mark.parametrize(
("expired", "terminated", "reason"),
[
(True, False, "Task expired before execution."),
(False, True, "Task terminated during execution."),
(False, False, "Task revoked before completion."),
],
)
def test_records_revocation_details(
self,
mocker,
expired,
terminated,
reason,
) -> None:
task = PaperlessTaskFactory(status=PaperlessTask.Status.PENDING)
request = mocker.MagicMock()
request.id = task.task_id
task_revoked_handler(
request=request,
expired=expired,
terminated=terminated,
)
task.refresh_from_db()
assert task.result_data == {
"reason": f"{reason} Check worker logs for details.",
}
def test_ignores_none_request(self) -> None:
"""task_revoked_handler must not raise when request is None."""
+8 -2
View File
@@ -1304,13 +1304,19 @@ class DocumentViewSet(
from documents.search import get_backend
get_backend().add_or_update(refreshed_doc)
document_updated.send(
sender=self.__class__,
document=refreshed_doc,
)
# Index the final workflow state, including deletion.
backend = get_backend()
final_doc = Document.objects.filter(pk=root_doc.pk).first()
if final_doc is None:
backend.remove(root_doc.pk)
else:
backend.add_or_update(final_doc)
return response
def list(self, request, *args, **kwargs):
+11 -11
View File
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-24 21:11+0000\n"
"POT-Creation-Date: 2026-10-28 02:55+0000\n"
"PO-Revision-Date: 2022-02-17 04:17\n"
"Last-Translator: \n"
"Language-Team: English\n"
@@ -1653,7 +1653,7 @@ msgid "workflow runs"
msgstr ""
#: documents/serialisers.py:483 documents/serialisers.py:840
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2724
#: documents/serialisers.py:2872 documents/views.py:360 documents/views.py:2730
#: paperless_mail/serialisers.py:156
msgid "Insufficient permissions."
msgstr ""
@@ -1694,7 +1694,7 @@ msgstr ""
msgid "Duplicate document identifiers are not allowed."
msgstr ""
#: documents/serialisers.py:2958 documents/views.py:4774
#: documents/serialisers.py:2958 documents/views.py:4780
#, python-format
msgid "Documents not found: %(ids)s"
msgstr ""
@@ -1949,36 +1949,36 @@ msgstr ""
msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr ""
#: documents/views.py:353 documents/views.py:2721
#: documents/views.py:353 documents/views.py:2727
msgid "Invalid more_like_id"
msgstr ""
#: documents/views.py:1659
#: documents/views.py:1665
msgid "Invalid AI configuration."
msgstr ""
#: documents/views.py:1670
#: documents/views.py:1676
msgid "AI backend request timed out."
msgstr ""
#: documents/views.py:1682
#: documents/views.py:1688
msgid "AI backend rejected the request. Check logs for details."
msgstr ""
#: documents/views.py:4790
#: documents/views.py:4796
#, python-format
msgid "Insufficient permissions to share document %(id)s."
msgstr ""
#: documents/views.py:4837
#: documents/views.py:4843
msgid "Bundle is already being processed."
msgstr ""
#: documents/views.py:4903
#: documents/views.py:4909
msgid "The share link bundle is still being prepared. Please try again later."
msgstr ""
#: documents/views.py:4917
#: documents/views.py:4923
msgid "The share link bundle is unavailable."
msgstr ""