mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-07-26 13:54:56 +00:00
Fix: prevent tag assignment from reverting other pending workflow assignments (#13178)
apply_assignment_to_document() mutated tags directly on the shared document instance via add_nested_tags(), whose m2m_changed signal triggers update_filename_and_move_files() -> instance.refresh_from_db(), discarding any not-yet-saved fields (e.g. storage_path) staged by an earlier-ordered action in the same workflow. Apply tag changes to a freshly-fetched instance instead, matching the pattern already used in apply_removal_to_document().
This commit is contained in:
@@ -2938,6 +2938,69 @@ class TestWorkflows(
|
||||
self.assertFalse(doc.tags.filter(pk=self.t1.pk).exists())
|
||||
self.assertTrue(doc.tags.filter(pk=self.t2.pk).exists())
|
||||
|
||||
def test_document_updated_workflow_assignment_storage_path_persists_with_tag_assignment(
|
||||
self,
|
||||
) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
- A document updated workflow filtered on a tag
|
||||
- One assignment action assigns a storage path, a second (later-ordered)
|
||||
assignment action adds a tag
|
||||
WHEN:
|
||||
- The document is updated and the workflow is triggered
|
||||
THEN:
|
||||
- Both the tag and the storage path are persisted
|
||||
"""
|
||||
trigger = WorkflowTrigger.objects.create(
|
||||
type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED,
|
||||
)
|
||||
trigger.filter_has_tags.add(self.t1)
|
||||
assign_storage_path = WorkflowAction.objects.create(
|
||||
type=WorkflowAction.WorkflowActionType.ASSIGNMENT,
|
||||
assign_storage_path=self.sp,
|
||||
order=0,
|
||||
)
|
||||
assign_tag = WorkflowAction.objects.create(
|
||||
type=WorkflowAction.WorkflowActionType.ASSIGNMENT,
|
||||
order=1,
|
||||
)
|
||||
assign_tag.assign_tags.add(self.t2)
|
||||
assign_tag.save()
|
||||
|
||||
workflow = Workflow.objects.create(
|
||||
name="Workflow assign storage path then tag",
|
||||
order=0,
|
||||
)
|
||||
workflow.triggers.add(trigger)
|
||||
workflow.actions.add(assign_storage_path, assign_tag)
|
||||
workflow.save()
|
||||
|
||||
doc = Document.objects.create(
|
||||
title="sample test",
|
||||
mime_type="application/pdf",
|
||||
checksum="assign-tag-and-storage-path",
|
||||
original_filename="sample.pdf",
|
||||
)
|
||||
generated = generate_unique_filename(doc)
|
||||
destination = (settings.ORIGINALS_DIR / generated).resolve()
|
||||
create_source_path_directory(destination)
|
||||
shutil.copy(self.SAMPLE_DIR / "simple.pdf", destination)
|
||||
Document.objects.filter(pk=doc.pk).update(filename=generated.as_posix())
|
||||
doc.refresh_from_db()
|
||||
doc.tags.set([self.t1])
|
||||
|
||||
superuser = User.objects.create_superuser("superuser")
|
||||
self.client.force_authenticate(user=superuser)
|
||||
self.client.patch(
|
||||
f"/api/documents/{doc.id}/",
|
||||
{"title": "user update to trigger workflow"},
|
||||
format="json",
|
||||
)
|
||||
|
||||
doc.refresh_from_db()
|
||||
self.assertEqual(doc.storage_path, self.sp)
|
||||
self.assertTrue(doc.tags.filter(pk=self.t2.pk).exists())
|
||||
|
||||
def test_removal_action_document_updated_removeall(self) -> None:
|
||||
"""
|
||||
GIVEN:
|
||||
|
||||
@@ -24,7 +24,11 @@ def apply_assignment_to_document(
|
||||
action: WorkflowAction, annotated with 'has_assign_*' boolean fields
|
||||
"""
|
||||
if action.has_assign_tags:
|
||||
document.add_nested_tags(action.assign_tags.all())
|
||||
# Apply to a freshly-fetched instance rather than the shared `document`.
|
||||
# Document.tags.add() fires an m2m_changed signal that ultimately calls
|
||||
# instance.refresh_from_db(), which would discard any other unsaved
|
||||
# assignment fields (e.g. storage_path) already staged on `document`.
|
||||
Document.objects.get(pk=document.pk).add_nested_tags(action.assign_tags.all())
|
||||
|
||||
if action.assign_correspondent:
|
||||
document.correspondent = action.assign_correspondent
|
||||
|
||||
Reference in New Issue
Block a user