]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Enhancement: "webui" workflowtrigger source option (#9170)
authorshamoon <4887959+shamoon@users.noreply.github.com>
Fri, 21 Feb 2025 16:26:00 +0000 (08:26 -0800)
committerGitHub <noreply@github.com>
Fri, 21 Feb 2025 16:26:00 +0000 (08:26 -0800)
src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts
src-ui/src/app/data/workflow-trigger.ts
src-ui/src/app/services/upload-documents.service.ts
src/documents/data_models.py
src/documents/migrations/1063_alter_workflowactionwebhook_url.py [deleted file]
src/documents/migrations/1063_alter_workflowactionwebhook_url_and_more.py [new file with mode: 0644]
src/documents/models.py
src/documents/serialisers.py
src/documents/tests/test_api_documents.py
src/documents/views.py

index 0908b69c043435d1818bbe5110e306a4927b0c95..5facc5ccef07d12cce39305efb04a01d13ed9b2b 100644 (file)
@@ -71,6 +71,10 @@ export const DOCUMENT_SOURCE_OPTIONS = [
     id: DocumentSource.MailFetch,
     name: $localize`Mail Fetch`,
   },
+  {
+    id: DocumentSource.WebUI,
+    name: $localize`Web UI`,
+  },
 ]
 
 export const SCHEDULE_DATE_FIELD_OPTIONS = [
index 12f76b7a3a75c9606f1664d19a66157587e02bc3..4299356b0677c5982e6c1b53e129d9a64f6a3211 100644 (file)
@@ -4,6 +4,7 @@ export enum DocumentSource {
   ConsumeFolder = 1,
   ApiUpload = 2,
   MailFetch = 3,
+  WebUI = 4,
 }
 
 export enum WorkflowTriggerType {
index 602e6d8ae1f87188468edc7b9219fc12054220f6..e2d1b52f4cec12e347bd15beb61f3434ce941b8d 100644 (file)
@@ -37,6 +37,7 @@ export class UploadDocumentsService {
   private uploadFile(file: File) {
     let formData = new FormData()
     formData.append('document', file, file.name)
+    formData.append('from_webui', 'true')
     let status = this.websocketStatusService.newFileUpload(file.name)
 
     status.message = $localize`Connecting...`
index 231e5900571e104e82909e3a04d0c7f964cf2ca1..406fe6b5aa491fcc3e4efc12c215d22bb428c3f9 100644 (file)
@@ -144,6 +144,7 @@ class DocumentSource(IntEnum):
     ConsumeFolder = 1
     ApiUpload = 2
     MailFetch = 3
+    WebUI = 4
 
 
 @dataclasses.dataclass
diff --git a/src/documents/migrations/1063_alter_workflowactionwebhook_url.py b/src/documents/migrations/1063_alter_workflowactionwebhook_url.py
deleted file mode 100644 (file)
index e249287..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated by Django 5.1.6 on 2025-02-16 16:31
-
-from django.db import migrations
-from django.db import models
-
-
-class Migration(migrations.Migration):
-    dependencies = [
-        ("documents", "1062_alter_savedviewfilterrule_rule_type"),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name="workflowactionwebhook",
-            name="url",
-            field=models.CharField(
-                help_text="The destination URL for the notification.",
-                max_length=256,
-                verbose_name="webhook url",
-            ),
-        ),
-    ]
diff --git a/src/documents/migrations/1063_alter_workflowactionwebhook_url_and_more.py b/src/documents/migrations/1063_alter_workflowactionwebhook_url_and_more.py
new file mode 100644 (file)
index 0000000..16c1eeb
--- /dev/null
@@ -0,0 +1,52 @@
+# Generated by Django 5.1.6 on 2025-02-20 04:55
+
+import multiselectfield.db.fields
+from django.db import migrations
+from django.db import models
+
+
+# WebUI source was added, so all existing APIUpload sources should be updated to include WebUI
+def update_workflow_sources(apps, schema_editor):
+    WorkflowTrigger = apps.get_model("documents", "WorkflowTrigger")
+    for trigger in WorkflowTrigger.objects.all():
+        sources = list(trigger.sources)
+        if 2 in sources:
+            sources.append(4)
+            trigger.sources = sources
+            trigger.save()
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("documents", "1062_alter_savedviewfilterrule_rule_type"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="workflowactionwebhook",
+            name="url",
+            field=models.CharField(
+                help_text="The destination URL for the notification.",
+                max_length=256,
+                verbose_name="webhook url",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="workflowtrigger",
+            name="sources",
+            field=multiselectfield.db.fields.MultiSelectField(
+                choices=[
+                    (1, "Consume Folder"),
+                    (2, "Api Upload"),
+                    (3, "Mail Fetch"),
+                    (4, "Web UI"),
+                ],
+                default="1,2,3,4",
+                max_length=7,
+            ),
+        ),
+        migrations.RunPython(
+            code=update_workflow_sources,
+            reverse_code=migrations.RunPython.noop,
+        ),
+    ]
index 4f9d3cb0ebd2f9dd19f6cdb4459fb1f6317234fb..b23bd8045f72ec6c5739c1e91999d15b6379f112 100644 (file)
@@ -1031,6 +1031,7 @@ class WorkflowTrigger(models.Model):
         CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder")
         API_UPLOAD = DocumentSource.ApiUpload.value, _("Api Upload")
         MAIL_FETCH = DocumentSource.MailFetch.value, _("Mail Fetch")
+        WEB_UI = DocumentSource.WebUI.value, _("Web UI")
 
     class ScheduleDateField(models.TextChoices):
         ADDED = "added", _("Added")
@@ -1045,9 +1046,9 @@ class WorkflowTrigger(models.Model):
     )
 
     sources = MultiSelectField(
-        max_length=5,
+        max_length=7,
         choices=DocumentSourceChoices.choices,
-        default=f"{DocumentSource.ConsumeFolder},{DocumentSource.ApiUpload},{DocumentSource.MailFetch}",
+        default=f"{DocumentSource.ConsumeFolder},{DocumentSource.ApiUpload},{DocumentSource.MailFetch},{DocumentSource.WebUI}",
     )
 
     filter_path = models.CharField(
index 75896ecdd22e7387116ed1c71d150f1796ff35bf..aeba5a721e53fbeb9bf2514ed44a1d0ab8a4925f 100644 (file)
@@ -1546,6 +1546,12 @@ class PostDocumentSerializer(serializers.Serializer):
         required=False,
     )
 
+    from_webui = serializers.BooleanField(
+        label="Documents are from Paperless-ngx WebUI",
+        write_only=True,
+        required=False,
+    )
+
     def validate_document(self, document):
         document_data = document.file.read()
         mime_type = magic.from_buffer(document_data, mime=True)
index a1bea944a04d9528bc6201f2898bb333a28b3a88..6247b0a6e4543a0c5621bbee27c8280e004ab408 100644 (file)
@@ -38,6 +38,7 @@ from documents.models import SavedView
 from documents.models import ShareLink
 from documents.models import StoragePath
 from documents.models import Tag
+from documents.models import WorkflowTrigger
 from documents.tests.utils import DirectoriesMixin
 from documents.tests.utils import DocumentConsumeDelayMixin
 
@@ -1362,6 +1363,30 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
         self.assertEqual(overrides.filename, "simple.pdf")
         self.assertEqual(overrides.custom_field_ids, [custom_field.id])
 
+    def test_upload_with_webui_source(self):
+        """
+        GIVEN: A document with a source file
+        WHEN: Upload the document with 'from_webui' flag
+        THEN: Consume is called with the source set as WebUI
+        """
+        self.consume_file_mock.return_value = celery.result.AsyncResult(
+            id=str(uuid.uuid4()),
+        )
+
+        with (Path(__file__).parent / "samples" / "simple.pdf").open("rb") as f:
+            response = self.client.post(
+                "/api/documents/post_document/",
+                {"document": f, "from_webui": True},
+            )
+
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+        self.consume_file_mock.assert_called_once()
+
+        input_doc, overrides = self.get_last_consume_delay_call_args()
+
+        self.assertEqual(input_doc.source, WorkflowTrigger.DocumentSourceChoices.WEB_UI)
+
     def test_upload_invalid_pdf(self):
         """
         GIVEN: Invalid PDF named "*.pdf" that mime_type is in settings.CONSUMER_PDF_RECOVERABLE_MIME_TYPES
index a856883f3c22eb69835df6b84c87259069ae1308..aceea66991e7a88c8981fe61de4fadda37e5eb49 100644 (file)
@@ -1385,6 +1385,7 @@ class PostDocumentView(GenericAPIView):
         created = serializer.validated_data.get("created")
         archive_serial_number = serializer.validated_data.get("archive_serial_number")
         custom_field_ids = serializer.validated_data.get("custom_fields")
+        from_webui = serializer.validated_data.get("from_webui")
 
         t = int(mktime(datetime.now().timetuple()))
 
@@ -1399,7 +1400,7 @@ class PostDocumentView(GenericAPIView):
         os.utime(temp_file_path, times=(t, t))
 
         input_doc = ConsumableDocument(
-            source=DocumentSource.ApiUpload,
+            source=DocumentSource.WebUI if from_webui else DocumentSource.ApiUpload,
             original_file=temp_file_path,
         )
         input_doc_overrides = DocumentMetadataOverrides(