Reusable app to have in-app notifications integrated with email and push notifications. Its built on top of django-notifications-hq.
Based on the Activity Streams Spec.
Notifications are actually actions events, which are categorized by four main components.
Actor. The object that performed the activity.Verb. The verb phrase that identifies the action of the activity.Action Object. (Optional) The object linked to the action itself.Target. (Optional) The object to which the activity was performed.
Actor, Action Object and Target are GenericForeignKeys to any
arbitrary Django object. An action is a description of an action that
was performed (Verb) at some instant in time by some Actor on some
optional Target that results in an Action Object getting
created/updated/deleted.
For example: nossila (actor)
opened (verb) pull request
18
(action_object) on
baseapp-backend
(target) 12 hours ago
- Finish implementing push notifications
- DRF views and serializers
Install the package with pip install baseapp-backend[notifications].
If you want to develop, install using this other guide.
1 - Add to your INSTALLED_APPS:
INSTALLED_APPS = [
"baseapp_notifications",
]2 - Set the notification and notification settings model in your settings/base.py:
NOTIFICATIONS_NOTIFICATION_MODEL = "notifications.Notification"
BASEAPP_NOTIFICATIONS_NOTIFICATIONSETTING_MODEL = "baseapp_notifications.NotificationSetting"Check how to customize to your own model bellow.
3 - Make sure to add the task routing for send_push_notification
CELERY_TASK_ROUTES = {
"baseapp_notifications.tasks.send_push_notification": {
"exchange": "default",
"routing_key": "default",
},
}4 - Make sure that your main User's DjangoObjectType implements interface NotificationsInterface:
from baseapp_core.graphql import DjangoObjectType, Node as RelayNode
from baseapp_core.plugins import graphql_shared_interfaces
class UserNode(DjangoObjectType):
class Meta:
interfaces = graphql_shared_interfaces.get(RelayNode, "NotificationsInterface")5 - Make sure your graphql.py main file is loading queries, mutations and subscriptions from plugin_registry.
1 - Add to your INSTALLED_APPS:
INSTALLED_APPS = [
"push_notifications"
]2 - Set the push notifications settings in your settings/base.py:
PUSH_NOTIFICATIONS_SETTINGS = {
"FCM_API_KEY": "[your api key]",
"APNS_CERTIFICATE": ["Absolute path to your APNS certificate file"],
"APNS_TOPIC": ["Apple app ID"],
"DEFAULT_CLOUD_MESSAGE_TYPE": "FCM",
"UPDATE_ON_DUPLICATE_REG_ID": True/False,
"APNS_USE_SANDBOX": True/False,
}You can get more details about this settings dict at the django-push-notifications oficial repository.
3 - Make sure your urls.py main file loads routes from the plugin_registry. The following push-notifications endpoints will be loaded automatically when push_notifications is installed:
- "push-notifications/apns": push_notifications.api.rest_framework.APNSDeviceAuthorizedViewSet
- "push-notifications/gcm": push_notifications.api.rest_framework.GCMDeviceAuthorizedViewSet
- "push-notifications/wns": push_notifications.api.rest_framework.WNSDeviceAuthorizedViewSet
- "push-notifications/web": push_notifications.api.rest_framework.WebPushDeviceAuthorizedViewSet
from baseapp_core.plugins import shared_services
if service := shared_services.get("notifications"):
service.send_notification(
add_to_history=True,
send_push=True,
send_email=True,
sender=user,
recipient=user,
verb="opened",
action_object=pr,
target=repository,
level="info",
description=_("{user_name} opened a pull request in {repository_name}").format(
user_name=user.name,
repository_name=repository.name
),
push_title=_("title"),
push_description=_("description"),
extra={},
)Arguments:
- add_to_history: A boolean (default=True). True to add this to your in-app notifications history.
- send_push: A boolean (default=True). True to send push notification to user's devices.
- send_email: A boolean (default=True). True to send notification via email.
- sender: An object of any type. (Required)
- recipient: A Group or a User QuerySet or a list of User. (Required)
- verb: An string. (Required)
- action_object: An object of any type. (Optional)
- target: An object of any type. (Optional)
- level: One of Notification.LEVELS ('success', 'info', 'warning', 'error') (default=info). (Optional)
- description: An string. (Optional)
- notification_url: URL used in emails so users can open this notification's page. (Optional)
- email_subject: An string (default=description). This will override the email's subject message. (Optional)
- email_message: An string (default=description). This will override the email's body message. (Optional)
- public: An boolean (default=True). (Optional)
- timestamp: An tzinfo (default=timezone.now()). (Optional)
- push_description: A string. (Required). The "body" of your push notification
- push_title: A string. (Optional). This will override the Title of your notification (apple and google uses the name defined on your build files)
- extra: A dict with data of any type. (Optional)
Extra data: ou can also send any arbitrary kwargs and they will be added to Notification.data JSONField.
To send email notifications make sure to set send_email=True argument and notification_url so users can open the notification in the browser. The description will be used both as email's subject and email's body by default, check how to customize bellow.
from baseapp_core.plugins import shared_services
if service := shared_services.get("notifications"):
service.send_notification(
sender=user,
recipient=user,
verb="opened",
description="email's subject",
add_to_history=True,
send_email=True,
notification_url="https://github.com/silverlogic/baseapp-backend/pull/18",
)By default it will look for templates based in your slugify(verb), so can implement the following files with the following content in your project for each verb you want to customize:
Create templates/emails/notifications/{verb_slugified}-subject.txt.j2 with:
{% include "emails/notification-subject.txt.j2" %}Create templates/emails/notifications/{verb_slugified}-body.txt.j2 with:
{% extends "emails/notification-body.txt.j2" %}Create templates/emails/notifications/{verb_slugified}-body.html.j2 with:
{% extends "emails/notification-body.html.j2" %}You can copy the extended templates over to your project to customize them as well.
Also check their source code in this repository to understand how you can customize the notification message for each notification's verb, for example, to customize the email notification message (defaults to what you passed to description):
{# templates/emails/notifications/opened-body.html.j2 #}
{% extends "emails/notification-body.html.j2" %}
{% block notification_message %}
{{ recipient.name }}'s custom notification message.
{% endblock %}In you GraphQL schema it will expose the following queries, mutations and subscriptions. Please check your GraphiQL playground for better understanding
query {
me {
notificationsUnreadCount
notifications
}
}mutation {
notificationsMarkAllAsRead(input: { read: true }) {
recipient { notificationsUnreadCount }
}
notificationsMarkAsRead(input: { notificationIds: ["b3b6c8e2-8f2a-4e3a-9c1d-2f7e6a1b2c3d", "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d"], read: true }) {
recipient { notificationsUnreadCount }
}
}subscription {
onNotificationChange {
createdNotification @prependEdge(connections: $connections) {
node {
...NotificationCardFragment
recipient {
id
notificationsUnreadCount
}
}
}
updatedNotification {
...NotificationCardFragment
}
deletedNotificationId @deleteRecord
}
}General development instructions can be found in main README.