mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-08 00:57:14 +00:00
Fix: bulk reprocess latest version for root documents
This commit is contained in:
4 files changed
+137
-5
No files matched your search
@@ -408,10 +408,16 @@ def reprocess(doc_ids: list[int], *, remote_ocr: bool = False) -> Literal["OK"]:
|
||||
|
||||
Consumption workflows do not run here, so ``remote_ocr`` is how the user
|
||||
asks for the remote engine when it is not configured to handle everything.
|
||||
|
||||
A root document with versions reprocesses its latest version, which is the
|
||||
file whose content, archive and thumbnail are shown for it.
|
||||
"""
|
||||
for document_id in doc_ids:
|
||||
for doc in Document.objects.select_related("root_document").filter(
|
||||
id__in=doc_ids,
|
||||
):
|
||||
pair = _resolve_root_and_source_doc(doc)
|
||||
update_document_content_maybe_archive_file.apply_async(
|
||||
kwargs={"document_id": document_id, "remote_ocr": remote_ocr},
|
||||
kwargs={"document_id": pair.source_doc.id, "remote_ocr": remote_ocr},
|
||||
headers={"trigger_source": PaperlessTask.TriggerSource.MANUAL},
|
||||
)
|
||||
|
||||
|
||||
@@ -490,18 +490,23 @@ def update_document_content_maybe_archive_file(
|
||||
shutil.move(thumbnail, document.thumbnail_path)
|
||||
|
||||
document.refresh_from_db()
|
||||
root_document = (
|
||||
document.root_document if document.root_document_id else document
|
||||
)
|
||||
logger.info(
|
||||
f"Updating index for document {document_id} ({document.archive_checksum})",
|
||||
f"Updating index for document {root_document.pk} ({document.archive_checksum})",
|
||||
)
|
||||
from documents.search import get_backend
|
||||
|
||||
get_backend().add_or_update(document)
|
||||
get_backend().add_or_update(root_document)
|
||||
|
||||
ai_config = AIConfig()
|
||||
if ai_config.llm_index_enabled:
|
||||
llm_index_add_or_update_document(document)
|
||||
llm_index_add_or_update_document(root_document)
|
||||
|
||||
clear_document_caches(document.pk)
|
||||
if root_document.pk != document.pk:
|
||||
clear_document_caches(root_document.pk)
|
||||
|
||||
except Exception:
|
||||
logger.exception(
|
||||
|
||||
@@ -2021,3 +2021,69 @@ class TestBulkEditReprocess(DirectoriesMixin, TestCase):
|
||||
self.assertEqual(mock_task.apply_async.call_count, 2)
|
||||
for call in mock_task.apply_async.call_args_list:
|
||||
self.assertTrue(call.kwargs["kwargs"]["remote_ocr"])
|
||||
|
||||
@mock.patch("documents.bulk_edit.update_document_content_maybe_archive_file")
|
||||
def test_reprocess_root_uses_latest_version(self, mock_task: mock.Mock) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
- A root document with two versions
|
||||
WHEN:
|
||||
- reprocess is called with the root document
|
||||
THEN:
|
||||
- The latest version is reprocessed, not the root's original file
|
||||
"""
|
||||
Document.objects.create(
|
||||
title="test",
|
||||
checksum="A-v1",
|
||||
mime_type="application/pdf",
|
||||
root_document=self.doc,
|
||||
version_index=1,
|
||||
)
|
||||
latest = Document.objects.create(
|
||||
title="test",
|
||||
checksum="A-v2",
|
||||
mime_type="application/pdf",
|
||||
root_document=self.doc,
|
||||
version_index=2,
|
||||
)
|
||||
|
||||
bulk_edit.reprocess([self.doc.id])
|
||||
|
||||
mock_task.apply_async.assert_called_once()
|
||||
self.assertEqual(
|
||||
mock_task.apply_async.call_args.kwargs["kwargs"]["document_id"],
|
||||
latest.id,
|
||||
)
|
||||
|
||||
@mock.patch("documents.bulk_edit.update_document_content_maybe_archive_file")
|
||||
def test_reprocess_explicit_version(self, mock_task: mock.Mock) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
- A root document with two versions
|
||||
WHEN:
|
||||
- reprocess is called with the older version
|
||||
THEN:
|
||||
- That version is reprocessed
|
||||
"""
|
||||
older = Document.objects.create(
|
||||
title="test",
|
||||
checksum="A-v1",
|
||||
mime_type="application/pdf",
|
||||
root_document=self.doc,
|
||||
version_index=1,
|
||||
)
|
||||
Document.objects.create(
|
||||
title="test",
|
||||
checksum="A-v2",
|
||||
mime_type="application/pdf",
|
||||
root_document=self.doc,
|
||||
version_index=2,
|
||||
)
|
||||
|
||||
bulk_edit.reprocess([older.id])
|
||||
|
||||
mock_task.apply_async.assert_called_once()
|
||||
self.assertEqual(
|
||||
mock_task.apply_async.call_args.kwargs["kwargs"]["document_id"],
|
||||
older.id,
|
||||
)
|
||||
@@ -287,6 +287,61 @@ class TestUpdateContent(DirectoriesMixin, TestCase):
|
||||
tasks.update_document_content_maybe_archive_file(doc.pk)
|
||||
self.assertNotEqual(Document.objects.get(pk=doc.pk).content, "test")
|
||||
|
||||
@mock.patch("documents.tasks.clear_document_caches")
|
||||
@mock.patch("documents.search.get_backend")
|
||||
def test_update_content_version_indexes_root(
|
||||
self,
|
||||
mock_get_backend: mock.Mock,
|
||||
mock_clear_caches: mock.Mock,
|
||||
) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
- A root document with a version
|
||||
WHEN:
|
||||
- Update content task is called for the version
|
||||
THEN:
|
||||
- The version's content is updated
|
||||
- The root document is indexed rather than the version
|
||||
- Caches are cleared for both
|
||||
"""
|
||||
sample1 = self.dirs.scratch_dir / "sample.pdf"
|
||||
shutil.copy(
|
||||
Path(__file__).parent
|
||||
/ "samples"
|
||||
/ "documents"
|
||||
/ "originals"
|
||||
/ "0000001.pdf",
|
||||
sample1,
|
||||
)
|
||||
root = Document.objects.create(
|
||||
title="test",
|
||||
content="root content",
|
||||
checksum="root",
|
||||
mime_type="application/pdf",
|
||||
)
|
||||
version = Document.objects.create(
|
||||
title="test",
|
||||
content="my document",
|
||||
checksum="wow",
|
||||
filename=sample1,
|
||||
mime_type="application/pdf",
|
||||
root_document=root,
|
||||
version_index=1,
|
||||
)
|
||||
|
||||
tasks.update_document_content_maybe_archive_file(version.pk)
|
||||
|
||||
self.assertNotEqual(
|
||||
Document.objects.get(pk=version.pk).content,
|
||||
"my document",
|
||||
)
|
||||
self.assertEqual(Document.objects.get(pk=root.pk).content, "root content")
|
||||
indexed = mock_get_backend.return_value.add_or_update.call_args.args[0]
|
||||
self.assertEqual(indexed.pk, root.pk)
|
||||
mock_clear_caches.assert_has_calls(
|
||||
[mock.call(version.pk), mock.call(root.pk)],
|
||||
)
|
||||
|
||||
|
||||
class TestUpdateContentRemoteOCR(DirectoriesMixin, TestCase):
|
||||
"""
|
||||
|
||||
Reference in new issue
Block a user