mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-05-01 11:19:32 -05:00
Messing around with notification action to start
This commit is contained in:
parent
cc93bc41df
commit
c4d59e0e77
@ -322,6 +322,17 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@case (WorkflowActionType.Notification) {
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<pngx-input-text i18n-title title="Notification subject" formControlName="notification_subject" [error]="error?.actions?.[i]?.notification_subject"></pngx-input-text>
|
||||
<pngx-input-text i18n-title title="Notification body" formControlName="notification_body" [error]="error?.actions?.[i]?.notification_body"></pngx-input-text>
|
||||
<pngx-input-text i18n-title title="Notification emails" formControlName="notification_destination_emails" [error]="error?.actions?.[i]?.notification_destination_emails"></pngx-input-text>
|
||||
<pngx-input-text i18n-title title="Notification url" formControlName="notification_destination_url" [error]="error?.actions?.[i]?.notification_destination_url"></pngx-input-text>
|
||||
<pngx-input-switch i18n-title title="Notification include document" formControlName="notification_include_document"></pngx-input-switch>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</ng-template>
|
||||
|
@ -96,6 +96,10 @@ export const WORKFLOW_ACTION_OPTIONS = [
|
||||
id: WorkflowActionType.Removal,
|
||||
name: $localize`Removal`,
|
||||
},
|
||||
{
|
||||
id: WorkflowActionType.Notification,
|
||||
name: $localize`Notification`,
|
||||
},
|
||||
]
|
||||
|
||||
const TRIGGER_MATCHING_ALGORITHMS = MATCHING_ALGORITHMS.filter(
|
||||
@ -402,6 +406,17 @@ export class WorkflowEditDialogComponent
|
||||
remove_all_custom_fields: new FormControl(
|
||||
action.remove_all_custom_fields
|
||||
),
|
||||
notification_subject: new FormControl(action.notification_subject),
|
||||
notification_body: new FormControl(action.notification_body),
|
||||
notification_destination_emails: new FormControl(
|
||||
action.notification_destination_emails
|
||||
),
|
||||
notification_destination_url: new FormControl(
|
||||
action.notification_destination_url
|
||||
),
|
||||
notification_include_document: new FormControl(
|
||||
action.notification_include_document
|
||||
),
|
||||
}),
|
||||
{ emitEvent }
|
||||
)
|
||||
@ -503,6 +518,11 @@ export class WorkflowEditDialogComponent
|
||||
remove_all_permissions: false,
|
||||
remove_custom_fields: [],
|
||||
remove_all_custom_fields: false,
|
||||
notification_subject: null,
|
||||
notification_body: null,
|
||||
notification_destination_emails: null,
|
||||
notification_destination_url: null,
|
||||
notification_include_document: null,
|
||||
}
|
||||
this.object.actions.push(action)
|
||||
this.createActionField(action)
|
||||
|
@ -3,6 +3,7 @@ import { ObjectWithId } from './object-with-id'
|
||||
export enum WorkflowActionType {
|
||||
Assignment = 1,
|
||||
Removal = 2,
|
||||
Notification = 3,
|
||||
}
|
||||
export interface WorkflowAction extends ObjectWithId {
|
||||
type: WorkflowActionType
|
||||
@ -62,4 +63,14 @@ export interface WorkflowAction extends ObjectWithId {
|
||||
remove_custom_fields?: number[] // [CustomField.id]
|
||||
|
||||
remove_all_custom_fields?: boolean
|
||||
|
||||
notification_subject?: string
|
||||
|
||||
notification_body?: string
|
||||
|
||||
notification_destination_emails?: string
|
||||
|
||||
notification_destination_url?: string
|
||||
|
||||
notification_include_document?: boolean
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ def settings(request):
|
||||
)
|
||||
|
||||
return {
|
||||
"EMAIL_ENABLED": django_settings.EMAIL_HOST != "localhost"
|
||||
or django_settings.EMAIL_HOST_USER != "",
|
||||
"EMAIL_ENABLED": django_settings.EMAIL_ENABLED,
|
||||
"DISABLE_REGULAR_LOGIN": django_settings.DISABLE_REGULAR_LOGIN,
|
||||
"REDIRECT_LOGIN_TO_SSO": django_settings.REDIRECT_LOGIN_TO_SSO,
|
||||
"ACCOUNT_ALLOW_SIGNUPS": django_settings.ACCOUNT_ALLOW_SIGNUPS,
|
||||
|
@ -0,0 +1,71 @@
|
||||
# Generated by Django 5.1.1 on 2024-10-23 17:15
|
||||
|
||||
from django.db import migrations
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("documents", "1055_alter_storagepath_path"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="workflowaction",
|
||||
name="notification_body",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="The body (message) of the notification, can include some placeholders, see documentation.",
|
||||
null=True,
|
||||
verbose_name="notification body",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="workflowaction",
|
||||
name="notification_destination_emails",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="The destination email addresses for the notification, comma separated.",
|
||||
null=True,
|
||||
verbose_name="notification destination emails",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="workflowaction",
|
||||
name="notification_destination_url",
|
||||
field=models.URLField(
|
||||
blank=True,
|
||||
help_text="The destination URL for the notification.",
|
||||
null=True,
|
||||
verbose_name="notification destination url",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="workflowaction",
|
||||
name="notification_include_document",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="include document in notification",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="workflowaction",
|
||||
name="notification_subject",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
help_text="The subject of the notification, can include some placeholders, see documentation.",
|
||||
max_length=256,
|
||||
null=True,
|
||||
verbose_name="notification subject",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="workflowaction",
|
||||
name="type",
|
||||
field=models.PositiveIntegerField(
|
||||
choices=[(1, "Assignment"), (2, "Removal"), (3, "Notification")],
|
||||
default=1,
|
||||
verbose_name="Workflow Action Type",
|
||||
),
|
||||
),
|
||||
]
|
@ -1166,6 +1166,10 @@ class WorkflowAction(models.Model):
|
||||
2,
|
||||
_("Removal"),
|
||||
)
|
||||
NOTIFICATION = (
|
||||
3,
|
||||
_("Notification"),
|
||||
)
|
||||
|
||||
type = models.PositiveIntegerField(
|
||||
_("Workflow Action Type"),
|
||||
@ -1367,6 +1371,48 @@ class WorkflowAction(models.Model):
|
||||
verbose_name=_("remove all custom fields"),
|
||||
)
|
||||
|
||||
notification_subject = models.CharField(
|
||||
_("notification subject"),
|
||||
max_length=256,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text=_(
|
||||
"The subject of the notification, can include some placeholders, "
|
||||
"see documentation.",
|
||||
),
|
||||
)
|
||||
|
||||
notification_body = models.TextField(
|
||||
_("notification body"),
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text=_(
|
||||
"The body (message) of the notification, can include some placeholders, "
|
||||
"see documentation.",
|
||||
),
|
||||
)
|
||||
|
||||
notification_destination_emails = models.TextField(
|
||||
_("notification destination emails"),
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text=_(
|
||||
"The destination email addresses for the notification, comma separated.",
|
||||
),
|
||||
)
|
||||
|
||||
notification_destination_url = models.URLField(
|
||||
_("notification destination url"),
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text=_("The destination URL for the notification."),
|
||||
)
|
||||
|
||||
notification_include_document = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name=_("include document in notification"),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("workflow action")
|
||||
verbose_name_plural = _("workflow actions")
|
||||
|
@ -1847,6 +1847,11 @@ class WorkflowActionSerializer(serializers.ModelSerializer):
|
||||
"remove_view_groups",
|
||||
"remove_change_users",
|
||||
"remove_change_groups",
|
||||
"notification_subject",
|
||||
"notification_body",
|
||||
"notification_destination_emails",
|
||||
"notification_destination_url",
|
||||
"notification_include_document",
|
||||
]
|
||||
|
||||
def validate(self, attrs):
|
||||
@ -1884,6 +1889,38 @@ class WorkflowActionSerializer(serializers.ModelSerializer):
|
||||
{"assign_title": f'Invalid f-string detected: "{e.args[0]}"'},
|
||||
)
|
||||
|
||||
if (
|
||||
"notification_subject" in attrs
|
||||
and attrs["notification_subject"] is not None
|
||||
and len(attrs["notification_subject"]) > 0
|
||||
and not (
|
||||
attrs["notification_destination_emails"]
|
||||
or attrs["notification_destination_url"]
|
||||
)
|
||||
):
|
||||
raise serializers.ValidationError(
|
||||
"Notification subject requires destination emails or URL",
|
||||
)
|
||||
|
||||
if (
|
||||
(
|
||||
(
|
||||
"notification_destination_emails" in attrs
|
||||
and attrs["notification_destination_emails"] is not None
|
||||
and len(attrs["notification_destination_emails"]) > 0
|
||||
)
|
||||
or (
|
||||
"notification_destination_url" in attrs
|
||||
and attrs["notification_destination_url"] is not None
|
||||
and len(attrs["notification_destination_url"]) > 0
|
||||
)
|
||||
)
|
||||
and not attrs["notification_subject"]
|
||||
and not attrs["notification_body"]
|
||||
):
|
||||
raise serializers.ValidationError(
|
||||
"Notification subject and body required",
|
||||
)
|
||||
return attrs
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@ import logging
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import httpx
|
||||
from celery import states
|
||||
from celery.signals import before_task_publish
|
||||
from celery.signals import task_failure
|
||||
@ -12,6 +13,7 @@ from django.contrib.admin.models import ADDITION
|
||||
from django.contrib.admin.models import LogEntry
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.mail import EmailMessage
|
||||
from django.db import DatabaseError
|
||||
from django.db import close_old_connections
|
||||
from django.db import models
|
||||
@ -866,6 +868,68 @@ def run_workflows(
|
||||
):
|
||||
overrides.custom_field_ids.remove(field.pk)
|
||||
|
||||
def notification_action():
|
||||
subject = parse_doc_title_w_placeholders(
|
||||
action.notification_subject,
|
||||
document.correspondent.name if document.correspondent else "",
|
||||
document.document_type.name if document.document_type else "",
|
||||
document.owner.username if document.owner else "",
|
||||
timezone.localtime(document.added),
|
||||
document.original_filename or "",
|
||||
timezone.localtime(document.created),
|
||||
)
|
||||
body = action.notification_body.format(
|
||||
title=subject,
|
||||
document=document,
|
||||
)
|
||||
# TODO: if doc exists, construct URL
|
||||
if action.notification_destination_emails:
|
||||
if not settings.EMAIL_ENABLED:
|
||||
logger.error(
|
||||
"Email backend has not been configured, cannot send email notifications",
|
||||
extra={"group": logging_group},
|
||||
)
|
||||
else:
|
||||
try:
|
||||
email = EmailMessage(
|
||||
subject=subject,
|
||||
body=body,
|
||||
to=action.notification_destination_emails.split(","),
|
||||
)
|
||||
if action.notification_include_document:
|
||||
email.attach_file(document.source_path)
|
||||
email.send()
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Error occurred sending notification email: {e}",
|
||||
extra={"group": logging_group},
|
||||
)
|
||||
if action.notification_destination_url:
|
||||
try:
|
||||
data = {
|
||||
"title": subject,
|
||||
"message": body,
|
||||
}
|
||||
files = None
|
||||
if action.notification_include_document:
|
||||
with open(document.source_path, "rb") as f:
|
||||
files = {"document": f}
|
||||
httpx.post(
|
||||
action.notification_destination_url,
|
||||
data=data,
|
||||
files=files,
|
||||
)
|
||||
else:
|
||||
httpx.post(
|
||||
action.notification_destination_url,
|
||||
data=data,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Error occurred sending notification to destination URL: {e}",
|
||||
extra={"group": logging_group},
|
||||
)
|
||||
|
||||
use_overrides = overrides is not None
|
||||
messages = []
|
||||
|
||||
@ -911,6 +975,8 @@ def run_workflows(
|
||||
assignment_action()
|
||||
elif action.type == WorkflowAction.WorkflowActionType.REMOVAL:
|
||||
removal_action()
|
||||
elif action.type == WorkflowAction.WorkflowActionType.NOTIFICATION:
|
||||
notification_action()
|
||||
|
||||
if not use_overrides:
|
||||
# save first before setting tags
|
||||
|
@ -1195,6 +1195,7 @@ DEFAULT_FROM_EMAIL: Final[str] = os.getenv("PAPERLESS_EMAIL_FROM", EMAIL_HOST_US
|
||||
EMAIL_USE_TLS: Final[bool] = __get_boolean("PAPERLESS_EMAIL_USE_TLS")
|
||||
EMAIL_USE_SSL: Final[bool] = __get_boolean("PAPERLESS_EMAIL_USE_SSL")
|
||||
EMAIL_SUBJECT_PREFIX: Final[str] = "[Paperless-ngx] "
|
||||
EMAIL_ENABLED = EMAIL_HOST != "localhost" or EMAIL_HOST_USER != ""
|
||||
if DEBUG: # pragma: no cover
|
||||
EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
|
||||
EMAIL_FILE_PATH = BASE_DIR / "sent_emails"
|
||||
|
Loading…
x
Reference in New Issue
Block a user