diff --git a/src/documents/apps.py b/src/documents/apps.py index 3683e3fbc..7ed006d06 100644 --- a/src/documents/apps.py +++ b/src/documents/apps.py @@ -9,9 +9,11 @@ class DocumentsConfig(AppConfig): def ready(self): from documents.signals import document_consumption_finished + from documents.signals import document_updated from documents.signals.handlers import add_inbox_tags from documents.signals.handlers import add_to_index - from documents.signals.handlers import run_workflows + from documents.signals.handlers import run_workflow_added + from documents.signals.handlers import run_workflow_updated from documents.signals.handlers import set_correspondent from documents.signals.handlers import set_document_type from documents.signals.handlers import set_log_entry @@ -25,6 +27,7 @@ class DocumentsConfig(AppConfig): document_consumption_finished.connect(set_storage_path) document_consumption_finished.connect(set_log_entry) document_consumption_finished.connect(add_to_index) - document_consumption_finished.connect(run_workflows) + document_consumption_finished.connect(run_workflow_added) + document_updated.connect(run_workflow_updated) AppConfig.ready(self) diff --git a/src/documents/matching.py b/src/documents/matching.py index 34e981797..dd3b40065 100644 --- a/src/documents/matching.py +++ b/src/documents/matching.py @@ -3,7 +3,6 @@ import re from fnmatch import fnmatch from documents.classifier import DocumentClassifier -from documents.data_models import ConsumableDocument from documents.data_models import DocumentSource from documents.models import Correspondent from documents.models import Document @@ -239,7 +238,7 @@ def _split_match(matching_model): def document_matches_workflow( - document: ConsumableDocument | Document, + document, # ConsumableDocument | Document workflow: Workflow, trigger_type: WorkflowTrigger.WorkflowTriggerType, ) -> bool: diff --git a/src/documents/migrations/1044_workflow_workflowaction_workflowtrigger_and_more.py b/src/documents/migrations/1044_workflow_workflowaction_workflowtrigger_and_more.py index c7106511a..a24ce2f25 100644 --- a/src/documents/migrations/1044_workflow_workflowaction_workflowtrigger_and_more.py +++ b/src/documents/migrations/1044_workflow_workflowaction_workflowtrigger_and_more.py @@ -404,7 +404,7 @@ class Migration(migrations.Migration): ), ), ( - "filter_has_correspondent", + "filter_has_document_type", models.ForeignKey( blank=True, null=True, @@ -414,7 +414,7 @@ class Migration(migrations.Migration): ), ), ( - "filter_has_document_type", + "filter_has_correspondent", models.ForeignKey( blank=True, null=True, diff --git a/src/documents/models.py b/src/documents/models.py index 5fab886d8..0880a146b 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -949,7 +949,7 @@ class WorkflowTrigger(models.Model): verbose_name=_("has these tag(s)"), ) - filter_has_correspondent = models.ForeignKey( + filter_has_document_type = models.ForeignKey( DocumentType, null=True, blank=True, @@ -957,7 +957,7 @@ class WorkflowTrigger(models.Model): verbose_name=_("has this document type"), ) - filter_has_document_type = models.ForeignKey( + filter_has_correspondent = models.ForeignKey( Correspondent, null=True, blank=True, diff --git a/src/documents/signals/__init__.py b/src/documents/signals/__init__.py index 393630008..fbb55d9fe 100644 --- a/src/documents/signals/__init__.py +++ b/src/documents/signals/__init__.py @@ -3,3 +3,4 @@ from django.dispatch import Signal document_consumption_started = Signal() document_consumption_finished = Signal() document_consumer_declaration = Signal() +document_updated = Signal() diff --git a/src/documents/signals/handlers.py b/src/documents/signals/handlers.py index 502626aa5..3fa10e95c 100644 --- a/src/documents/signals/handlers.py +++ b/src/documents/signals/handlers.py @@ -519,14 +519,22 @@ def add_to_index(sender, document, **kwargs): index.add_or_update_document(document) -def run_workflows(sender, document: Document, logging_group=None, **kwargs): +def run_workflow_added(sender, document: Document, logging_group=None, **kwargs): + run_workflow(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED, document) + + +def run_workflow_updated(sender, document: Document, logging_group=None, **kwargs): + run_workflow(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, document) + + +def run_workflow(trigger_type: WorkflowTrigger.WorkflowTriggerType, document: Document): for workflow in Workflow.objects.filter( - triggers__type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED, + triggers__type=trigger_type, ).order_by("order"): if matching.document_matches_workflow( document, workflow, - WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED, + trigger_type, ): for action in workflow.actions.all(): if action.assign_tags.all().count() > 0: diff --git a/src/documents/tasks.py b/src/documents/tasks.py index d0728a719..2b1449737 100644 --- a/src/documents/tasks.py +++ b/src/documents/tasks.py @@ -36,6 +36,7 @@ from documents.models import Tag from documents.parsers import DocumentParser from documents.parsers import get_parser_class_for_mime_type from documents.sanity_checker import SanityCheckFailedException +from documents.signals import document_updated if settings.AUDIT_LOG_ENABLED: import json @@ -215,6 +216,10 @@ def bulk_update_documents(document_ids): ix = index.open_index() for doc in documents: + document_updated.send( + sender=None, + document=doc, + ) post_save.send(Document, instance=doc, created=False) with AsyncWriter(ix) as writer: diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index bd6bc3299..0c248104a 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -1,12 +1,12 @@ from datetime import timedelta from pathlib import Path -from unittest import TestCase from unittest import mock import pytest from django.contrib.auth.models import Group from django.contrib.auth.models import User from django.utils import timezone +from rest_framework.test import APITestCase from documents import tasks from documents.data_models import ConsumableDocument @@ -28,7 +28,7 @@ from paperless_mail.models import MailRule @pytest.mark.django_db -class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, TestCase): +class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase): SAMPLE_DIR = Path(__file__).parent / "samples" def setUp(self) -> None: @@ -626,7 +626,6 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, TestCase): def test_document_added_workflow(self): trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED, - sources=f"{DocumentSource.ApiUpload},{DocumentSource.ConsumeFolder},{DocumentSource.MailFetch}", filter_filename="*sample*", ) action = WorkflowAction.objects.create( @@ -671,3 +670,35 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, TestCase): self.assertEqual(doc.correspondent, self.c2) self.assertEqual(doc.title, f"Doc created in {created.year}") + + def test_document_updated_workflow(self): + trigger = WorkflowTrigger.objects.create( + type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, + filter_has_document_type=self.dt, + ) + action = WorkflowAction.objects.create() + action.assign_custom_fields.add(self.cf1) + w = Workflow.objects.create( + name="Workflow 1", + order=0, + ) + w.triggers.add(trigger) + w.actions.add(action) + w.save() + + doc = Document.objects.create( + title="sample test", + correspondent=self.c, + original_filename="sample.pdf", + ) + + superuser = User.objects.create_superuser("superuser") + self.client.force_authenticate(user=superuser) + + self.client.patch( + f"/api/documents/{doc.id}/", + {"document_type": self.dt.id}, + format="json", + ) + + self.assertEqual(doc.custom_fields.all().count(), 1) diff --git a/src/documents/views.py b/src/documents/views.py index 261a12017..84633cc03 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -116,6 +116,7 @@ from documents.serialisers import UiSettingsViewSerializer from documents.serialisers import WorkflowActionSerializer from documents.serialisers import WorkflowSerializer from documents.serialisers import WorkflowTriggerSerializer +from documents.signals import document_updated from documents.tasks import consume_file from paperless import version from paperless.db import GnuPG @@ -324,6 +325,12 @@ class DocumentViewSet( from documents import index index.add_or_update_document(self.get_object()) + + document_updated.send( + sender=self.__class__, + document=self.get_object(), + ) + return response def destroy(self, request, *args, **kwargs):