Enhancement: "webui" workflowtrigger source option

This commit is contained in:
shamoon 2025-02-19 21:01:42 -08:00
parent 3bf64ae7da
commit 82307ac289
No known key found for this signature in database
10 changed files with 95 additions and 25 deletions

View File

@ -71,6 +71,10 @@ export const DOCUMENT_SOURCE_OPTIONS = [
id: DocumentSource.MailFetch, id: DocumentSource.MailFetch,
name: $localize`Mail Fetch`, name: $localize`Mail Fetch`,
}, },
{
id: DocumentSource.WebUI,
name: $localize`Web UI`,
},
] ]
export const SCHEDULE_DATE_FIELD_OPTIONS = [ export const SCHEDULE_DATE_FIELD_OPTIONS = [

View File

@ -4,6 +4,7 @@ export enum DocumentSource {
ConsumeFolder = 1, ConsumeFolder = 1,
ApiUpload = 2, ApiUpload = 2,
MailFetch = 3, MailFetch = 3,
WebUI = 4,
} }
export enum WorkflowTriggerType { export enum WorkflowTriggerType {

View File

@ -37,6 +37,7 @@ export class UploadDocumentsService {
private uploadFile(file: File) { private uploadFile(file: File) {
let formData = new FormData() let formData = new FormData()
formData.append('document', file, file.name) formData.append('document', file, file.name)
formData.append('from_webui', 'true')
let status = this.websocketStatusService.newFileUpload(file.name) let status = this.websocketStatusService.newFileUpload(file.name)
status.message = $localize`Connecting...` status.message = $localize`Connecting...`

View File

@ -144,6 +144,7 @@ class DocumentSource(IntEnum):
ConsumeFolder = 1 ConsumeFolder = 1
ApiUpload = 2 ApiUpload = 2
MailFetch = 3 MailFetch = 3
WebUI = 4
@dataclasses.dataclass @dataclasses.dataclass

View File

@ -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",
),
),
]

View File

@ -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,
),
]

View File

@ -1031,6 +1031,7 @@ class WorkflowTrigger(models.Model):
CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder") CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder")
API_UPLOAD = DocumentSource.ApiUpload.value, _("Api Upload") API_UPLOAD = DocumentSource.ApiUpload.value, _("Api Upload")
MAIL_FETCH = DocumentSource.MailFetch.value, _("Mail Fetch") MAIL_FETCH = DocumentSource.MailFetch.value, _("Mail Fetch")
WEB_UI = DocumentSource.WebUI.value, _("Web UI")
class ScheduleDateField(models.TextChoices): class ScheduleDateField(models.TextChoices):
ADDED = "added", _("Added") ADDED = "added", _("Added")
@ -1045,9 +1046,9 @@ class WorkflowTrigger(models.Model):
) )
sources = MultiSelectField( sources = MultiSelectField(
max_length=5, max_length=7,
choices=DocumentSourceChoices.choices, 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( filter_path = models.CharField(

View File

@ -1546,6 +1546,12 @@ class PostDocumentSerializer(serializers.Serializer):
required=False, required=False,
) )
from_webui = serializers.BooleanField(
label="Documents are from Paperless-ngx WebUI",
write_only=True,
required=False,
)
def validate_document(self, document): def validate_document(self, document):
document_data = document.file.read() document_data = document.file.read()
mime_type = magic.from_buffer(document_data, mime=True) mime_type = magic.from_buffer(document_data, mime=True)

View File

@ -38,6 +38,7 @@ from documents.models import SavedView
from documents.models import ShareLink from documents.models import ShareLink
from documents.models import StoragePath from documents.models import StoragePath
from documents.models import Tag from documents.models import Tag
from documents.models import WorkflowTrigger
from documents.tests.utils import DirectoriesMixin from documents.tests.utils import DirectoriesMixin
from documents.tests.utils import DocumentConsumeDelayMixin from documents.tests.utils import DocumentConsumeDelayMixin
@ -1362,6 +1363,30 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
self.assertEqual(overrides.filename, "simple.pdf") self.assertEqual(overrides.filename, "simple.pdf")
self.assertEqual(overrides.custom_field_ids, [custom_field.id]) 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): def test_upload_invalid_pdf(self):
""" """
GIVEN: Invalid PDF named "*.pdf" that mime_type is in settings.CONSUMER_PDF_RECOVERABLE_MIME_TYPES GIVEN: Invalid PDF named "*.pdf" that mime_type is in settings.CONSUMER_PDF_RECOVERABLE_MIME_TYPES

View File

@ -1385,6 +1385,7 @@ class PostDocumentView(GenericAPIView):
created = serializer.validated_data.get("created") created = serializer.validated_data.get("created")
archive_serial_number = serializer.validated_data.get("archive_serial_number") archive_serial_number = serializer.validated_data.get("archive_serial_number")
custom_field_ids = serializer.validated_data.get("custom_fields") custom_field_ids = serializer.validated_data.get("custom_fields")
from_webui = serializer.validated_data.get("from_webui")
t = int(mktime(datetime.now().timetuple())) t = int(mktime(datetime.now().timetuple()))
@ -1399,7 +1400,7 @@ class PostDocumentView(GenericAPIView):
os.utime(temp_file_path, times=(t, t)) os.utime(temp_file_path, times=(t, t))
input_doc = ConsumableDocument( input_doc = ConsumableDocument(
source=DocumentSource.ApiUpload, source=DocumentSource.WebUI if from_webui else DocumentSource.ApiUpload,
original_file=temp_file_path, original_file=temp_file_path,
) )
input_doc_overrides = DocumentMetadataOverrides( input_doc_overrides = DocumentMetadataOverrides(