How to modify notifications¶
This guide will show you how you can configure and modify all things related to notifications.
Templates¶
In order to provide your own customized templates or override parts of existing ones, templates can be placed in the <my-site>/templates/semantic-ui/invenio_notifications
folder. The file name then has to match the base template name (e.g. community-submission.submitted.jinja
). So we end up with
<my-site>/templates/semantic-ui/invenio_notifications/community-submission.submitted.jinja
Let's have a look at a base template and then customize parts of it for our own needs.
Assume a notification context like this:
{
"request": {
"links": {
"self_html": "<link to the request>",
},
"created_by": {
"id": 3,
"username": "Chris the Creator",
},
"receiver": {
"id": "3fc4fcaa-ce2c-4ec7-97cd-4b29ca204035",
"metadata": {
"title": "Notification Community",
},
"links": {
"self_html": "<link to the community>",
}
},
"topic": {
"id": "49e72dea-f14a-4774-a52d-a3d581fed86e",
"metadata": {
"title": "My Submitted Record",
},
}
}
}
{# notifications/community-submission.submitted.jinja #}
{%- block subject -%}
New record submission for your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} submitted by {{ notification.context.get("request").get("created_by").get("username") }}
{%- endblock subject -%}
{%- block html_body -%}
<p>The record "{{ notification.context.get("request").get("topic").get("metadata").get("title") }}" was submitted to your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} by {{ notification.context.get("request").get("created_by").get("username") }}.</p>
<a href="{{ notification.context.get("request").get("links").get("self_html") }}" class="button">Review the request</a>
{%- endblock html_body -%}
{%- block plain_body -%}
The record "{{ notification.context.get("request").get("topic").get("metadata").get("title") }}" was submitted to your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} by {{ notification.context.get("request").get("created_by").get("username") }}.
Review the request: {{ notification.context.get("request").get("links").get("self_html") }}
{%- endblock plain_body -%}
{# Markdown for Slack/Mattermost/chat #}
{%- block md_body -%}
The record "{{ notification.context.get("request").get("topic").get("metadata").get("title") }}" was submitted to your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} by {{ notification.context.get("request").get("created_by").get("username")}}.
[Review the request]({{ notification.context.get("request").get("links").get("self_html") }})
{%- endblock md_body -%}
We are pretty happy with most of the content, but want to override the html_body
to include a link to the community and all requests.
To do this, we will create a file with the same name, copy the file content from the base file and then adapt the block we want to modify.
{# notifications/community-submission.submitted.jinja #}
{%- block subject -%}
New record submission for your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} submitted by {{ notification.context.get("request").get("created_by").get("username") }}
{%- endblock subject -%}
{% block html_body %}
<p>The record "{{ notification.context.get("request").get("topic").get("metadata").get("title") }}" was submitted to your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} by {{ notification.context.get("request").get("created_by").get("username") }}.</p>
<a href="{{ notification.context.get("request").get("receiver").get("links").get("self_html") }}" class="button">Check out the community"</a>
<a href="{{ notification.context.get("request").get("links").get("self_html") }}" class="button">Review the request</a>
<a href="{{ notification.context.get("request").get("receiver").get("links").get("self_html") + "/requests" }}" class="button">Check out all community requests</a>
{% endblock %}
{%- block plain_body -%}
The record "{{ notification.context.get("request").get("topic").get("metadata").get("title") }}" was submitted to your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} by {{ notification.context.get("request").get("created_by").get("username") }}.
Review the request: {{ notification.context.get("request").get("links").get("self_html") }}
{%- endblock plain_body -%}
{# Markdown for Slack/Mattermost/chat #}
{%- block md_body -%}
The record "{{ notification.context.get("request").get("topic").get("metadata").get("title") }}" was submitted to your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} by {{ notification.context.get("request").get("created_by").get("username")}}.
[Review the request]({{ notification.context.get("request").get("links").get("self_html") }})
{%- endblock md_body -%}
If you want to provide a template for a specific backend, you can do that too! Assume we want to add a specific template for the email backend. We know that the id
of the email backend is email
. Following the same steps as above and adding the backend id to the path, we end up with a file to be placed in
<my-site>/templates/semantic-ui/invenio_notifications/email/community-submission.submitted.jinja
In a backend specific file, you only have to provide blocks needed by this specific backend (but feel free to include other blocks). The email relies on the subject
, plain_body
and html_body
blocks.
In our case, we are happy with the content in the general template and only want to modify the html_body
block (as in the example before). Now, we can take advantage of the base template by extending it.
{% extends "invenio_notifications/community-submission.submitted.html" %}
{% block html_body %}
<p>The record "{{ notification.context.get("request").get("topic").get("metadata").get("title") }}" was submitted to your community {{ notification.context.get("request").get("receiver").get("metadata").get("title") }} by {{ notification.context.get("request").get("created_by").get("username") }}.</p>
<a href="{{ notification.context.get("request").get("receiver").get("links").get("self_html") }}" class="button">Check out the community"</a>
<a href="{{ notification.context.get("request").get("links").get("self_html") }}" class="button">Review the request</a>
<a href="{{ notification.context.get("request").get("receiver").get("links").get("self_html") + "/requests" }}" class="button">Check out all community requests</a>
{% endblock %}
Only the specified blocks will be overriden. Other blocks stay as they are in the base template.
Build your own¶
This will show you can build your own notification classes.
Notification Backend¶
Building your own notification backend can be achieved in a few steps. For instance, you can provide an implementation for your institution's preferred communication tool and send notifications via this backend. For this, simply extend the NotificationBackend
class and implement the send
method.
from invenio_notifications.backends import JinjaTemplateLoaderMixin, NotificationBackend,
class InstitutationalBackend(NotificationBackend, JinjaTemplateLoaderMixin):
"""Base class for notification backends."""
id = "institutional-backend"
"""Unique id of the backend."""
def send(self, notification, recipient):
"""Send the notification message as markdown to a user."""
template = self.render_template(notification=notification, recipient=recipient)
institutation_communication_tool.send_message(user_id=recipient.data["id"], template["md_body"])
Notification Builder¶
Let us assume that you want to override who will get notified in the event of a community record submission (community curator and owner) and add the previously defined backend (so recipients will get notified via whatever the base class has defined and via the InstitutationalBackend
).
To do this, we will create a custom builder, which will inherit most of the properties from the existing base class.
from institutational_package.notifications import InstitutationalBackend
from invenio_communities.notifications.generators import CommunityMembersRecipient
from invenio_rdm_records.notifications.builders import CommunityInclusionSubmittedNotificationBuilder
class CustomSubmissionBuilder(CommunityInclusionSubmittedNotificationBuilder):
# properties not overwritten will keep their base value
recipients = [
CommunityMembersRecipient(key="request.receiver", roles=["curator", "owner"]),
]
recipient_backends = CommunityInclusionSubmittedNotificationBuilder.recipient_backends + [
InstitutationalBackend(),
]
Configuration Values¶
Configuration values used in the invenio-notifications
module can be overriden, in order to adapt instances to specific needs.
NOTIFICATION_BACKENDS¶
This config variable allows to specify the available backends. For a detailed description on backends, checkout the respective reference section. For instance, you can provide an implementation for your institution's preferred communication tool and send notifications via this backend.
As an example, take the backend shown in build your own backend. Then you only have to specify it in the config variable (e.g. in invenio.cfg
).
NOTIFICATION_BACKENDS = {
EmailNotificationBackend.id: EmailNotificationBackend,
InstitutationalBackend.id: InstitutationalBackend,
}
NOTIFICATION_BUILDERS¶
Specifies notification builders to be used for certain types of notifications. When a notification is handled by the manager, it will lookup the type in this variable and build the notification with the provided builder class.
As an example, take the backend shown in build your own builder. Then you only have to specify it in the config variable (e.g. in invenio.cfg
).
NOTIFICATIONS_BUILDERS = {
CustomSubmissionBuilder.type: CustomSubmissionBuilder,
}
Since the custom builder uses the same type
as the builder we want to override, we can use either type
as key for the entry. The following snippet will have the same effect, but it is more clear what will be overriden.
NOTIFICATIONS_BUILDERS = {
CommunityInclusionSubmittedNotificationBuilder.type: CustomSubmissionBuilder,
}
NOTIFICATIONS_ENTITY_RESOLVERS¶
Specifies entity resolvers to be used for resolving the notification context. These are usually ServiceResultResolver
objects, which provide functionality to dump an object to a reference dictionary and later on use the dump to fetch information as seen on the API/service level (i.e. fully resolved objects with links for easy access).
NOTIFICATIONS_ENTITY_RESOLVERS = [
RDMRecordServiceResultResolver(),
ServiceResultResolver(service_id="users", type_key="user"),
ServiceResultResolver(service_id="communities", type_key="community"),
ServiceResultResolver(service_id="requests", type_key="request"),
ServiceResultResolver(service_id="request_events", type_key="request_event"),
]