Skip to content

Commit

Permalink
Allow customizing notification templates per project (#3369)
Browse files Browse the repository at this point in the history
* project specific templates
  • Loading branch information
vindex10 authored May 15, 2023
1 parent 4416b2d commit 5a05be2
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 10 deletions.
50 changes: 50 additions & 0 deletions docs/docs/administration/settings/messaging.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Messaging

Dispatch supports sending email notifications to participants of, for example, an incident.

## Notification templates

Templates for emails are [part](https://github.com/Netflix/dispatch/tree/master/src/dispatch/messaging/email/templates) of Dispatch
and are [Jinja](https://jinja.palletsprojects.com/) templates that during runtime are compiled into [MJML](https://mjml.io/) format.

There is a way to customize these templates. To do this, if you run Dispatch with [Docker Compose](https://github.com/Netflix/dispatch-docker/),
mount a volume with a customized templates dir as part of the docker compose:

```
web:
image: dispatch-local
...
volumes:
- "../dispatch-templates/messaging-email-templates:/usr/local/lib/python3.11/site-packages/dispatch/messaging/email/templates"
```

Such approach allows you to customize the common template for *all projects*.

You can also "patch" the templates *per project*. Create a folder per project (identified by project id):

```
dispatch/messaging/email/templates/project_id/<project_id>/base.mjml
```

This will be used at the first place if exists,
otherwise the resolution process will gracefully fall back to the default template:

```
dispatch/messaging/email/templates/base.mjml
```


## Markdown in the notifications

:::warning
Watch out for security implications related to unescaped HTML that may propagate through the system.
:::

By default, notification text is just a plain text with special characters and HTML escaped.

It is possible, however, to enable Markdown syntax with a server setting:

```
DISPATCH_MARKDOWN_IN_INCIDENT_DESC=True
DISPATCH_ESCAPE_HTML=False
```
27 changes: 19 additions & 8 deletions src/dispatch/messaging/email/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import subprocess
import tempfile

import jinja2.exceptions
from dispatch.config import MJML_PATH


Expand All @@ -20,7 +21,7 @@
log = logging.getLogger(__name__)


def get_template(message_type: MessageType):
def get_template(message_type: MessageType, project_id: int):
"""Fetches the correct template based on the message type."""
template_map = {
MessageType.incident_executive_report: ("executive_report.mjml", None),
Expand All @@ -45,19 +46,27 @@ def get_template(message_type: MessageType):
),
}

template_path, description = template_map.get(message_type, (None, None))
template_key, description = template_map.get(message_type, (None, None))

if not template_path:
if not template_key:
raise Exception(f"Unable to determine template. MessageType: {message_type}")

return env.get_template(os.path.join("templates", template_path)), description
try:
template_path = os.path.join("templates", "project_id", f"{project_id}", template_key)
template = env.get_template(template_path)
except jinja2.exceptions.TemplateNotFound:
template_path = os.path.join("templates", template_key)
template = env.get_template(template_path)
log.debug("Resolved template path: %s", template_path)

return template, description


def create_multi_message_body(
message_template: dict, message_type: MessageType, items: list, **kwargs
message_template: dict, message_type: MessageType, items: list, project_id: int, **kwargs
):
"""Creates a multi message message body based on message type."""
template, description = get_template(message_type)
template, description = get_template(message_type, project_id)

master_map = []
for item in items:
Expand All @@ -67,9 +76,11 @@ def create_multi_message_body(
return render_html(template.render(**kwargs))


def create_message_body(message_template: dict, message_type: MessageType, **kwargs):
def create_message_body(
message_template: dict, message_type: MessageType, project_id: int, **kwargs
):
"""Creates the correct message body based on message type."""
template, description = get_template(message_type)
template, description = get_template(message_type, project_id)

items_grouped_rendered = []
if kwargs.get("items_grouped"):
Expand Down
6 changes: 4 additions & 2 deletions src/dispatch/plugins/dispatch_google/gmail/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,12 @@ def send(
cc = kwargs["cc"]

if not items:
message_body = create_message_body(notification_template, notification_type, **kwargs)
message_body = create_message_body(
notification_template, notification_type, self.project_id, **kwargs
)
else:
message_body = create_multi_message_body(
notification_template, notification_type, items, **kwargs
notification_template, notification_type, items, self.project_id, **kwargs
)

html_message = create_html_message(
Expand Down

0 comments on commit 5a05be2

Please sign in to comment.