diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html index 0f415b8d7..042729f2f 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.html @@ -323,27 +323,29 @@ } @case (WorkflowActionType.Email) { -
+
+
- - - - + + + +
} @case (WorkflowActionType.Webhook) { -
+
+
- - - @if (formGroup.get('webhook_use_params').value) { - + + + @if (formGroup.get('webhook').value['use_params']) { + } @else { - + } - - + +
} diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts index 28a0e8bc0..ade5e2f31 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.spec.ts @@ -347,4 +347,15 @@ describe('WorkflowEditDialogComponent', () => { component.actionFields.at(0).get('remove_change_groups').disabled ).toBeFalsy() }) + + it('should prune empty nested objects on save', () => { + component.object = workflow + component.addTrigger() + component.addAction() + expect(component.objectForm.get('actions').value[0].email).not.toBeNull() + expect(component.objectForm.get('actions').value[0].webhook).not.toBeNull() + component.save() + expect(component.objectForm.get('actions').value[0].email).toBeNull() + expect(component.objectForm.get('actions').value[0].webhook).toBeNull() + }) }) diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts index f2b2b7752..e5aa32267 100644 --- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts +++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts @@ -410,18 +410,22 @@ export class WorkflowEditDialogComponent remove_all_custom_fields: new FormControl( action.remove_all_custom_fields ), - email_subject: new FormControl(action.email_subject), - email_body: new FormControl(action.email_body), - email_to: new FormControl(action.email_to), - email_include_document: new FormControl(action.email_include_document), - webhook_url: new FormControl(action.webhook_url), - webhook_use_params: new FormControl(action.webhook_use_params), - webhook_params: new FormControl(action.webhook_params), - webhook_body: new FormControl(action.webhook_body), - webhook_headers: new FormControl(action.webhook_headers), - webhook_include_document: new FormControl( - action.webhook_include_document - ), + email: new FormGroup({ + id: new FormControl(action.email?.id), + subject: new FormControl(action.email?.subject), + body: new FormControl(action.email?.body), + to: new FormControl(action.email?.to), + include_document: new FormControl(!!action.email?.include_document), + }), + webhook: new FormGroup({ + id: new FormControl(action.webhook?.id), + url: new FormControl(action.webhook?.url), + use_params: new FormControl(action.webhook?.use_params), + params: new FormControl(action.webhook?.params), + body: new FormControl(action.webhook?.body), + headers: new FormControl(action.webhook?.headers), + include_document: new FormControl(!!action.webhook?.include_document), + }), }), { emitEvent } ) @@ -523,16 +527,22 @@ export class WorkflowEditDialogComponent remove_all_permissions: false, remove_custom_fields: [], remove_all_custom_fields: false, - email_subject: null, - email_body: null, - email_to: null, - email_include_document: false, - webhook_url: null, - webhook_use_params: true, - webhook_params: null, - webhook_body: null, - webhook_headers: null, - webhook_include_document: false, + email: { + id: null, + subject: null, + body: null, + to: null, + include_document: false, + }, + webhook: { + id: null, + url: null, + use_params: true, + params: null, + body: null, + headers: null, + include_document: false, + }, } this.object.actions.push(action) this.createActionField(action) @@ -563,4 +573,18 @@ export class WorkflowEditDialogComponent c.get('id').setValue(null, { emitEvent: false }) ) } + + save(): void { + this.objectForm + .get('actions') + .value.forEach((action: WorkflowAction, i) => { + if (action.type !== WorkflowActionType.Webhook) { + action.webhook = null + } + if (action.type !== WorkflowActionType.Email) { + action.email = null + } + }) + super.save() + } } diff --git a/src-ui/src/app/data/workflow-action.ts b/src-ui/src/app/data/workflow-action.ts index fdb8914e4..b802d47b4 100644 --- a/src-ui/src/app/data/workflow-action.ts +++ b/src-ui/src/app/data/workflow-action.ts @@ -6,6 +6,31 @@ export enum WorkflowActionType { Email = 3, Webhook = 4, } + +export interface WorkflowActionEmail extends ObjectWithId { + subject?: string + + body?: string + + to?: string + + include_document?: boolean +} + +export interface WorkflowActionWebhook extends ObjectWithId { + url?: string + + use_params?: boolean + + params?: object + + body?: string + + headers?: object + + include_document?: boolean +} + export interface WorkflowAction extends ObjectWithId { type: WorkflowActionType @@ -65,23 +90,7 @@ export interface WorkflowAction extends ObjectWithId { remove_all_custom_fields?: boolean - email_subject?: string + email?: WorkflowActionEmail - email_body?: string - - email_to?: string - - email_include_document?: boolean - - webhook_url?: string - - webhook_use_params?: boolean - - webhook_params?: object - - webhook_body?: string - - webhook_headers?: object - - webhook_include_document?: boolean + webhook?: WorkflowActionWebhook } diff --git a/src/documents/migrations/1059_workflowaction_email_body_and_more.py b/src/documents/migrations/1059_workflowaction_email_body_and_more.py deleted file mode 100644 index e5718f3a7..000000000 --- a/src/documents/migrations/1059_workflowaction_email_body_and_more.py +++ /dev/null @@ -1,119 +0,0 @@ -# Generated by Django 5.1.3 on 2024-11-24 18:30 - -from django.db import migrations -from django.db import models - - -class Migration(migrations.Migration): - dependencies = [ - ("documents", "1058_workflowtrigger_schedule_date_custom_field_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="workflowaction", - name="email_body", - field=models.TextField( - blank=True, - help_text="The body (message) of the email, can include some placeholders, see documentation.", - null=True, - verbose_name="email body", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="email_include_document", - field=models.BooleanField( - default=False, - verbose_name="include document in email", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="email_subject", - field=models.CharField( - blank=True, - help_text="The subject of the email, can include some placeholders, see documentation.", - max_length=256, - null=True, - verbose_name="email subject", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="email_to", - field=models.TextField( - blank=True, - help_text="The destination email addresses, comma separated.", - null=True, - verbose_name="emails to", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="webhook_body", - field=models.TextField( - blank=True, - help_text="The body to send with the webhook URL if parameters not used.", - null=True, - verbose_name="webhook body", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="webhook_headers", - field=models.JSONField( - blank=True, - help_text="The headers to send with the webhook URL.", - null=True, - verbose_name="webhook headers", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="webhook_include_document", - field=models.BooleanField( - default=False, - verbose_name="include document in webhook", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="webhook_params", - field=models.JSONField( - blank=True, - help_text="The parameters to send with the webhook URL if body not used.", - null=True, - verbose_name="webhook parameters", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="webhook_url", - field=models.URLField( - blank=True, - help_text="The destination URL for the notification.", - null=True, - verbose_name="webhook url", - ), - ), - migrations.AddField( - model_name="workflowaction", - name="webhook_use_params", - field=models.BooleanField(default=True, verbose_name="use parameters"), - ), - migrations.AlterField( - model_name="workflowaction", - name="type", - field=models.PositiveIntegerField( - choices=[ - (1, "Assignment"), - (2, "Removal"), - (3, "Email"), - (4, "Webhook"), - ], - default=1, - verbose_name="Workflow Action Type", - ), - ), - ] diff --git a/src/documents/migrations/1059_workflowactionemail_workflowactionwebhook_and_more.py b/src/documents/migrations/1059_workflowactionemail_workflowactionwebhook_and_more.py new file mode 100644 index 000000000..d94470285 --- /dev/null +++ b/src/documents/migrations/1059_workflowactionemail_workflowactionwebhook_and_more.py @@ -0,0 +1,154 @@ +# Generated by Django 5.1.3 on 2024-11-26 04:07 + +import django.db.models.deletion +from django.db import migrations +from django.db import models + + +class Migration(migrations.Migration): + dependencies = [ + ("documents", "1058_workflowtrigger_schedule_date_custom_field_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="WorkflowActionEmail", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "subject", + models.CharField( + help_text="The subject of the email, can include some placeholders, see documentation.", + max_length=256, + verbose_name="email subject", + ), + ), + ( + "body", + models.TextField( + help_text="The body (message) of the email, can include some placeholders, see documentation.", + verbose_name="email body", + ), + ), + ( + "to", + models.TextField( + help_text="The destination email addresses, comma separated.", + verbose_name="emails to", + ), + ), + ( + "include_document", + models.BooleanField( + default=False, + verbose_name="include document in email", + ), + ), + ], + ), + migrations.CreateModel( + name="WorkflowActionWebhook", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "url", + models.URLField( + help_text="The destination URL for the notification.", + verbose_name="webhook url", + ), + ), + ( + "use_params", + models.BooleanField(default=True, verbose_name="use parameters"), + ), + ( + "params", + models.JSONField( + blank=True, + help_text="The parameters to send with the webhook URL if body not used.", + null=True, + verbose_name="webhook parameters", + ), + ), + ( + "body", + models.TextField( + blank=True, + help_text="The body to send with the webhook URL if parameters not used.", + null=True, + verbose_name="webhook body", + ), + ), + ( + "headers", + models.JSONField( + blank=True, + help_text="The headers to send with the webhook URL.", + null=True, + verbose_name="webhook headers", + ), + ), + ( + "include_document", + models.BooleanField( + default=False, + verbose_name="include document in webhook", + ), + ), + ], + ), + migrations.AlterField( + model_name="workflowaction", + name="type", + field=models.PositiveIntegerField( + choices=[ + (1, "Assignment"), + (2, "Removal"), + (3, "Email"), + (4, "Webhook"), + ], + default=1, + verbose_name="Workflow Action Type", + ), + ), + migrations.AddField( + model_name="workflowaction", + name="email", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="action", + to="documents.workflowactionemail", + verbose_name="email", + ), + ), + migrations.AddField( + model_name="workflowaction", + name="webhook", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="action", + to="documents.workflowactionwebhook", + verbose_name="webhook", + ), + ), + ] diff --git a/src/documents/models.py b/src/documents/models.py index 2befcdb9c..5aa69a13e 100644 --- a/src/documents/models.py +++ b/src/documents/models.py @@ -1156,6 +1156,85 @@ class WorkflowTrigger(models.Model): return f"WorkflowTrigger {self.pk}" +class WorkflowActionEmail(models.Model): + subject = models.CharField( + _("email subject"), + max_length=256, + null=False, + help_text=_( + "The subject of the email, can include some placeholders, " + "see documentation.", + ), + ) + + body = models.TextField( + _("email body"), + null=False, + help_text=_( + "The body (message) of the email, can include some placeholders, " + "see documentation.", + ), + ) + + to = models.TextField( + _("emails to"), + null=False, + help_text=_( + "The destination email addresses, comma separated.", + ), + ) + + include_document = models.BooleanField( + default=False, + verbose_name=_("include document in email"), + ) + + def __str__(self): + return f"Workflow Email Action {self.pk}" + + +class WorkflowActionWebhook(models.Model): + url = models.URLField( + _("webhook url"), + null=False, + help_text=_("The destination URL for the notification."), + ) + + use_params = models.BooleanField( + default=True, + verbose_name=_("use parameters"), + ) + + params = models.JSONField( + _("webhook parameters"), + null=True, + blank=True, + help_text=_("The parameters to send with the webhook URL if body not used."), + ) + + body = models.TextField( + _("webhook body"), + null=True, + blank=True, + help_text=_("The body to send with the webhook URL if parameters not used."), + ) + + headers = models.JSONField( + _("webhook headers"), + null=True, + blank=True, + help_text=_("The headers to send with the webhook URL."), + ) + + include_document = models.BooleanField( + default=False, + verbose_name=_("include document in webhook"), + ) + + def __str__(self): + return f"Workflow Webhook Action {self.pk}" + + class WorkflowAction(models.Model): class WorkflowActionType(models.IntegerChoices): ASSIGNMENT = ( @@ -1375,77 +1454,22 @@ class WorkflowAction(models.Model): verbose_name=_("remove all custom fields"), ) - email_subject = models.CharField( - _("email subject"), - max_length=256, + email = models.ForeignKey( + WorkflowActionEmail, null=True, blank=True, - help_text=_( - "The subject of the email, can include some placeholders, " - "see documentation.", - ), + on_delete=models.SET_NULL, + related_name="action", + verbose_name=_("email"), ) - email_body = models.TextField( - _("email body"), + webhook = models.ForeignKey( + WorkflowActionWebhook, null=True, blank=True, - help_text=_( - "The body (message) of the email, can include some placeholders, " - "see documentation.", - ), - ) - - email_to = models.TextField( - _("emails to"), - null=True, - blank=True, - help_text=_( - "The destination email addresses, comma separated.", - ), - ) - - email_include_document = models.BooleanField( - default=False, - verbose_name=_("include document in email"), - ) - - webhook_url = models.URLField( - _("webhook url"), - null=True, - blank=True, - help_text=_("The destination URL for the notification."), - ) - - webhook_use_params = models.BooleanField( - default=True, - verbose_name=_("use parameters"), - ) - - webhook_params = models.JSONField( - _("webhook parameters"), - null=True, - blank=True, - help_text=_("The parameters to send with the webhook URL if body not used."), - ) - - webhook_body = models.TextField( - _("webhook body"), - null=True, - blank=True, - help_text=_("The body to send with the webhook URL if parameters not used."), - ) - - webhook_headers = models.JSONField( - _("webhook headers"), - null=True, - blank=True, - help_text=_("The headers to send with the webhook URL."), - ) - - webhook_include_document = models.BooleanField( - default=False, - verbose_name=_("include document in webhook"), + on_delete=models.SET_NULL, + related_name="action", + verbose_name=_("webhook"), ) class Meta: diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index bee6ee044..6e1aa7044 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -49,6 +49,8 @@ from documents.models import Tag from documents.models import UiSettings from documents.models import Workflow from documents.models import WorkflowAction +from documents.models import WorkflowActionEmail +from documents.models import WorkflowActionWebhook from documents.models import WorkflowTrigger from documents.parsers import is_mime_type_supported from documents.permissions import get_groups_with_only_permission @@ -1807,12 +1809,44 @@ class WorkflowTriggerSerializer(serializers.ModelSerializer): return attrs +class WorkflowActionEmailSerializer(serializers.ModelSerializer): + id = serializers.IntegerField(allow_null=True, required=False) + + class Meta: + model = WorkflowActionEmail + fields = [ + "id", + "subject", + "body", + "to", + "include_document", + ] + + +class WorkflowActionWebhookSerializer(serializers.ModelSerializer): + id = serializers.IntegerField(allow_null=True, required=False) + + class Meta: + model = WorkflowActionWebhook + fields = [ + "id", + "url", + "use_params", + "params", + "body", + "headers", + "include_document", + ] + + class WorkflowActionSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=False, allow_null=True) assign_correspondent = CorrespondentField(allow_null=True, required=False) assign_tags = TagsField(many=True, allow_null=True, required=False) assign_document_type = DocumentTypeField(allow_null=True, required=False) assign_storage_path = StoragePathField(allow_null=True, required=False) + email = WorkflowActionEmailSerializer(allow_null=True, required=False) + webhook = WorkflowActionWebhookSerializer(allow_null=True, required=False) class Meta: model = WorkflowAction @@ -1847,15 +1881,8 @@ class WorkflowActionSerializer(serializers.ModelSerializer): "remove_view_groups", "remove_change_users", "remove_change_groups", - "email_to", - "email_subject", - "email_body", - "email_include_document", - "webhook_url", - "webhook_use_params", - "webhook_params", - "webhook_body", - "webhook_headers", + "email", + "webhook", ] def validate(self, attrs): @@ -1893,37 +1920,22 @@ class WorkflowActionSerializer(serializers.ModelSerializer): {"assign_title": f'Invalid f-string detected: "{e.args[0]}"'}, ) - if "type" in attrs and attrs["type"] == WorkflowAction.WorkflowActionType.EMAIL: - if ( - "email_subject" not in attrs - or attrs["email_subject"] is None - or len(attrs["email_subject"]) == 0 - or "email_body" not in attrs - or attrs["email_body"] is None - or len(attrs["email_body"]) == 0 - ): - raise serializers.ValidationError( - "Email subject and body required", - ) - elif ( - "email_to" not in attrs - or attrs["email_to"] is None - or len(attrs["email_to"]) == 0 - ): - raise serializers.ValidationError( - "Email recipient required", - ) + if ( + "type" in attrs + and attrs["type"] == WorkflowAction.WorkflowActionType.EMAIL + and "email" not in attrs + ): + raise serializers.ValidationError( + "Email data is required for email actions", + ) if ( "type" in attrs and attrs["type"] == WorkflowAction.WorkflowActionType.WEBHOOK - ) and ( - "webhook_url" not in attrs - or attrs["webhook_url"] is None - or len(attrs["webhook_url"]) == 0 + and "webhook" not in attrs ): raise serializers.ValidationError( - "Webhook URL required", + "Webhook data is required for webhook actions", ) return attrs @@ -1980,11 +1992,34 @@ class WorkflowSerializer(serializers.ModelSerializer): remove_change_users = action.pop("remove_change_users", None) remove_change_groups = action.pop("remove_change_groups", None) + email_data = action.pop("email", None) + webhook_data = action.pop("webhook", None) + action_instance, _ = WorkflowAction.objects.update_or_create( id=action.get("id"), defaults=action, ) + if email_data is not None: + serializer = WorkflowActionEmailSerializer(data=email_data) + serializer.is_valid(raise_exception=True) + email, _ = WorkflowActionEmail.objects.update_or_create( + id=email_data.get("id"), + defaults=serializer.validated_data, + ) + action_instance.email = email + action_instance.save() + + if webhook_data is not None: + serializer = WorkflowActionWebhookSerializer(data=webhook_data) + serializer.is_valid(raise_exception=True) + webhook, _ = WorkflowActionWebhook.objects.update_or_create( + id=webhook_data.get("id"), + defaults=serializer.validated_data, + ) + action_instance.webhook = webhook + action_instance.save() + if assign_tags is not None: action_instance.assign_tags.set(assign_tags) if assign_view_users is not None: @@ -2037,6 +2072,9 @@ class WorkflowSerializer(serializers.ModelSerializer): if action.workflows.all().count() == 0: action.delete() + WorkflowActionEmail.objects.filter(action=None).delete() + WorkflowActionWebhook.objects.filter(action=None).delete() + def create(self, validated_data) -> Workflow: if "triggers" in validated_data: triggers = validated_data.pop("triggers") diff --git a/src/documents/signals/handlers.py b/src/documents/signals/handlers.py index e3344a656..22b282b63 100644 --- a/src/documents/signals/handlers.py +++ b/src/documents/signals/handlers.py @@ -891,7 +891,7 @@ def run_workflows( added = timezone.localtime(document.added) created = timezone.localtime(document.created) subject = parse_w_workflow_placeholders( - action.email_subject, + action.email.subject, correspondent, document_type, owner_username, @@ -902,7 +902,7 @@ def run_workflows( doc_url, ) body = parse_w_workflow_placeholders( - action.email_body, + action.email.body, correspondent, document_type, owner_username, @@ -916,13 +916,13 @@ def run_workflows( email = EmailMessage( subject=subject, body=body, - to=action.email_to.split(","), + to=action.email.to.split(","), ) - if action.email_include_document: + if action.email.include_document: email.attach_file(document.source_path) n_messages = email.send() logger.debug( - f"Sent {n_messages} notification email(s) to {action.email_to}", + f"Sent {n_messages} notification email(s) to {action.email.to}", extra={"group": logging_group}, ) except Exception as e: @@ -949,9 +949,9 @@ def run_workflows( try: data = {} - if action.webhook_use_params: + if action.webhook.use_params: try: - for key, value in action.webhook_params.items(): + for key, value in action.webhook.params.items(): data[key] = parse_w_workflow_placeholders( value, correspondent, @@ -970,7 +970,7 @@ def run_workflows( ) else: data = parse_w_workflow_placeholders( - action.webhook_body, + action.webhook.body, correspondent, document_type, owner_username, @@ -981,30 +981,30 @@ def run_workflows( doc_url, ) headers = {} - if action.webhook_headers: + if action.webhook.headers: try: headers = { - str(k): str(v) for k, v in action.webhook_headers.items() + str(k): str(v) for k, v in action.webhook.headers.items() } except Exception as e: logger.error( f"Error occurred parsing webhook headers: {e}", extra={"group": logging_group}, ) - if action.webhook_include_document: + if action.webhook.include_document: with open(document.source_path, "rb") as f: files = { "file": (document.original_filename, f, document.mime_type), } httpx.post( - action.webhook_url, + action.webhook.url, data=data, files=files, headers=headers, ) else: httpx.post( - action.webhook_url, + action.webhook.url, data=data, headers=headers, ) diff --git a/src/documents/tests/test_api_workflows.py b/src/documents/tests/test_api_workflows.py index 711f304f6..9a13021c3 100644 --- a/src/documents/tests/test_api_workflows.py +++ b/src/documents/tests/test_api_workflows.py @@ -484,8 +484,10 @@ class TestApiWorkflows(DirectoriesMixin, APITestCase): "actions": [ { "type": WorkflowAction.WorkflowActionType.EMAIL, - "email_subject": "Subject", - "email_body": "Body", + "email": { + "subject": "Subject", + "body": "Body", + }, }, ], }, @@ -511,9 +513,12 @@ class TestApiWorkflows(DirectoriesMixin, APITestCase): "actions": [ { "type": WorkflowAction.WorkflowActionType.EMAIL, - "email_subject": "Subject", - "email_body": "Body", - "email_to": "me@example.com", + "email": { + "subject": "Subject", + "body": "Body", + "to": "me@example.com", + "include_document": False, + }, }, ], }, @@ -572,7 +577,10 @@ class TestApiWorkflows(DirectoriesMixin, APITestCase): "actions": [ { "type": WorkflowAction.WorkflowActionType.WEBHOOK, - "webhook_url": "https://example.com", + "webhook": { + "url": "https://example.com", + "include_document": False, + }, }, ], }, diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index e7deb5dfd..97f6b37fd 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -31,6 +31,8 @@ from documents.models import StoragePath from documents.models import Tag from documents.models import Workflow from documents.models import WorkflowAction +from documents.models import WorkflowActionEmail +from documents.models import WorkflowActionWebhook from documents.models import WorkflowRun from documents.models import WorkflowTrigger from documents.signals import document_consumption_finished @@ -2109,12 +2111,15 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) + email_action = WorkflowActionEmail.objects.create( + subject="Test Notification: {doc_title}", + body="Test message: {doc_url}", + to="user@example.com", + include_document=False, + ) action = WorkflowAction.objects.create( type=WorkflowAction.WorkflowActionType.EMAIL, - email_subject="Test Notification: {doc_title}", - email_body="Test message: {doc_url}", - email_to="user@example.com", - email_include_document=False, + email=email_action, ) w = Workflow.objects.create( name="Workflow 1", @@ -2161,12 +2166,15 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) + email_action = WorkflowActionEmail.objects.create( + subject="Test Notification: {doc_title}", + body="Test message: {doc_url}", + to="me@example.com", + include_document=True, + ) action = WorkflowAction.objects.create( type=WorkflowAction.WorkflowActionType.EMAIL, - email_subject="Test Notification: {doc_title}", - email_body="Test message: {doc_url}", - email_to="me@example.com", - email_include_document=True, + email=email_action, ) w = Workflow.objects.create( name="Workflow 1", @@ -2202,11 +2210,14 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) + email_action = WorkflowActionEmail.objects.create( + subject="Test Notification: {doc_title}", + body="Test message: {doc_url}", + to="me@example.com", + ) action = WorkflowAction.objects.create( type=WorkflowAction.WorkflowActionType.EMAIL, - email_subject="Test Notification: {doc_title}", - email_body="Test message: {doc_url}", - email_to="me@example.com", + email=email_action, ) w = Workflow.objects.create( name="Workflow 1", @@ -2247,11 +2258,14 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) + email_action = WorkflowActionEmail.objects.create( + subject="Test Notification: {doc_title}", + body="Test message: {doc_url}", + to="me@example.com", + ) action = WorkflowAction.objects.create( type=WorkflowAction.WorkflowActionType.EMAIL, - email_subject="Test Notification: {doc_title}", - email_body="Test message: {doc_url}", - email_to="me@example.com", + email=email_action, ) w = Workflow.objects.create( name="Workflow 1", @@ -2296,12 +2310,15 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) + webhook_action = WorkflowActionWebhook.objects.create( + use_params=False, + body="Test message: {doc_url}", + url="http://paperless-ngx.com", + include_document=False, + ) action = WorkflowAction.objects.create( type=WorkflowAction.WorkflowActionType.WEBHOOK, - webhook_use_params=False, - webhook_body="Test message: {doc_url}", - webhook_url="http://paperless-ngx.com", - webhook_include_document=False, + webhook=webhook_action, ) w = Workflow.objects.create( name="Workflow 1", @@ -2348,12 +2365,15 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) + webhook_action = WorkflowActionWebhook.objects.create( + use_params=False, + body="Test message: {doc_url}", + url="http://paperless-ngx.com", + include_document=True, + ) action = WorkflowAction.objects.create( type=WorkflowAction.WorkflowActionType.WEBHOOK, - webhook_use_params=False, - webhook_body="Test message: {doc_url}", - webhook_url="http://paperless-ngx.com", - webhook_include_document=True, + webhook=webhook_action, ) w = Workflow.objects.create( name="Workflow 1", @@ -2373,6 +2393,7 @@ class TestWorkflows( correspondent=self.c, original_filename="simple.pdf", filename=test_file, + mime_type="application/pdf", ) run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc) @@ -2380,7 +2401,7 @@ class TestWorkflows( mock_post.assert_called_once_with( "http://paperless-ngx.com", data=f"Test message: http://localhost:8000/documents/{doc.id}/", - files={"file": ("simple.pdf", mock.ANY)}, + files={"file": ("simple.pdf", mock.ANY, "application/pdf")}, headers={}, ) @@ -2402,15 +2423,18 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) - action = WorkflowAction.objects.create( - type=WorkflowAction.WorkflowActionType.WEBHOOK, - webhook_use_params=True, - webhook_params={ + webhook_action = WorkflowActionWebhook.objects.create( + use_params=True, + params={ "title": "Test webhook: {doc_title}", "body": "Test message: {doc_url}", }, - webhook_url="http://paperless-ngx.com", - webhook_include_document=True, + url="http://paperless-ngx.com", + include_document=True, + ) + action = WorkflowAction.objects.create( + type=WorkflowAction.WorkflowActionType.WEBHOOK, + webhook=webhook_action, ) w = Workflow.objects.create( name="Workflow 1", @@ -2447,12 +2471,15 @@ class TestWorkflows( trigger = WorkflowTrigger.objects.create( type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, ) + webhook_action = WorkflowActionWebhook.objects.create( + url="http://paperless-ngx.com", + use_params=True, + params="invalid", + headers="invalid", + ) action = WorkflowAction.objects.create( type=WorkflowAction.WorkflowActionType.WEBHOOK, - webhook_url="http://paperless-ngx.com", - webhook_use_params=True, - webhook_params="invalid", - webhook_headers="invalid", + webhook=webhook_action, ) w = Workflow.objects.create( name="Workflow 1",