Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
notify
: Notification framework¶
The lino.modlib.notify
plugin adds a notification framework to your
Lino application.
We assume that you have read the end-user documentation in The notify plugin.
You can play with notifications in the demo projects chatter
,
noi1e
and noi1r
. Open two browsers windows (one of them private)
and sign in as two different users. Then write a comment in one window and note
the desktop notification received by the other user.
Code snippets on this page are tested in the chatter demo project.
Side note: Code snippets (lines starting with >>>
) in this document get
tested as part of our development workflow. The following
initialization snippet tells you which demo project is being used in
this document.
>>> import lino
>>> lino.startup('lino_book.projects.chatter.settings')
>>> from lino.api.doctest import *
Concepts¶
This page will introduce the following new concepts:
- notification message¶
Stored in
Message
.- push notification¶
A technology used to implement desktop notifications.
https://rossta.net/blog/using-the-web-push-api-with-vapid.html
- push subscription¶
The fact that a site user has given permission to some of their browsers to show desktop notifications for this site.
Usage¶
Add lino.modlib.notify
to your
lino.core.site.Site.get_installed_plugins()
.
To emit a notification message from your application code, you can
call
Message.emit_broadcast_notification()
.have your model(s) inherit from
ChangeNotifier
.add actions that inherit from
NotifyingAction
.
You can use this plugin without enabling desktop notifications. In that case the site users will receive only email notifications and/or dashboard notifications.
How to activate desktop notifications¶
To enable desktop notifications, there are some requirements:
Set
use_linod
to True to enable desktop notification that is done through websockets or the push-api. use_linod will enable websockets notifications by default but to have notifications through push-api setuse_push_api
to True. See:lino.modlib.linod
.Run
pm install
in order to install additional Python modules (pywebpush and/or django-channels and channels-redis).To test push notifications on a development server, you must Set up a public URL for your development server.
To enable push notifications on a production site, the server administrator must also Configure VAPID credentials.
Set up a public URL for your development server¶
The Push API requires your web server to be publicly reachable via https. One method to do this for a development server is to use ngrok.
Install ngrok: https://ngrok.com/download
Run ngrok:
$ ngrok http 8000
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account joe@example.com (Plan: Free)
Version 2.3.40
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://b3735559b89b.ngrok.io -> http://localhost:8000
Forwarding https://b3735559b89b.ngrok.io -> http://localhost:8000
Connections ttl opn rt1 rt5 p50 p90
268 0 0.00 0.00 0.50 1.39
In most terminals you can then Ctrl-click on the https://b3735559b89b.ngrok.io URL to open your browser on it.
Configure VAPID credentials¶
More about the Push API¶
- Push API¶
A technology for delivering desktop notifications.
Currently a Working Draft published by the W3C Web Applications Working Group, and intended to become a W3C Recommendation.
Unlike alternative technologies like WebSockets or server-sent events, the Push API uses a third-party push server.
Subject and body of a notification message¶
As an application developer you should understand the different meanings of “subject” and “body”:
The body is expected to be a self-sufficient and complete description of the event. If a message has a body, then the subject is not being displayed in the MyMessages summary.
The subject might contain limited rich text (text formatting, links) but be aware that this formatting may get lost when the message is sent as an email or as a desktop notification.
Notification messages¶
You can use
to see all notification messages.>>> # run_menu_command("Explorer --> System --> Notification messages")
>>> rt.show('notify.AllMessages')
============================ ============================================================== ================ ============= ====== =====================
Created Subject Recipient Reply to seen sent
---------------------------- -------------------------------------------------------------- ---------------- ------------- ------ ---------------------
2024-04-06 05:48:00 Broadcast message
2024-04-06 05:48:00 Welcome on board, Andreas. Andy 2024-04-06 05:48:00
2024-04-06 05:48:00 Welcome on board, Albert. Bert 2024-04-06 05:48:00
2024-04-06 05:48:00 Welcome on board, Chloe. Chloe Cleoment 2024-04-06 05:48:00
2024-04-06 05:48:00 Welcome on board, Robin. Robin Rood 2024-04-06 05:48:00
... Andy commented on Harry Potter Bert Comment #7
... Bert commented on Harry Potter Andy Comment #8
... Chloe Cleoment commented on Harry Potter Andy Comment #9
... Chloe Cleoment commented on Harry Potter Bert Comment #9
... Robin Rood commented on Harry Potter Andy Comment #10
... Robin Rood commented on Harry Potter Bert Comment #10
... Andy commented on Harry Potter Bert Comment #11
... Bert commented on Harry Potter Andy Comment #12
... Chloe Cleoment commented on Harry Potter Andy Comment #13
... Chloe Cleoment commented on Harry Potter Bert Comment #13
... Robin Rood commented on Star Trek Chloe Cleoment Comment #14
... Andy commented on Star Trek Chloe Cleoment Comment #15
... Andy commented on Star Trek Robin Rood Comment #15
... Bert commented on Star Trek Chloe Cleoment Comment #16
... Bert commented on Star Trek Robin Rood Comment #16
... Chloe Cleoment commented on Star Trek Robin Rood Comment #17
... Robin Rood commented on Star Trek Chloe Cleoment Comment #18
... Andy commented on Star Trek Chloe Cleoment Comment #19
... Andy commented on Star Trek Robin Rood Comment #19
... Bert commented on Star Trek Chloe Cleoment Comment #20
... Bert commented on Star Trek Robin Rood Comment #20
... Chloe Cleoment commented on Hitchhiker's Guide to the Galaxy Andy Comment #21
... Chloe Cleoment commented on Hitchhiker's Guide to the Galaxy Bert Comment #21
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Andy Comment #22
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Bert Comment #22
... Andy commented on Hitchhiker's Guide to the Galaxy Bert Comment #23
... Bert commented on Hitchhiker's Guide to the Galaxy Andy Comment #24
... Chloe Cleoment commented on Hitchhiker's Guide to the Galaxy Andy Comment #25
... Chloe Cleoment commented on Hitchhiker's Guide to the Galaxy Bert Comment #25
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Andy Comment #26
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Bert Comment #26
... Andy commented on Hitchhiker's Guide to the Galaxy Bert Comment #27
... Bert commented on Harry Potter Andy Comment #28
... Chloe Cleoment commented on Harry Potter Andy Comment #29
... Chloe Cleoment commented on Harry Potter Bert Comment #29
... Robin Rood commented on Harry Potter Andy Comment #30
... Robin Rood commented on Harry Potter Bert Comment #30
... Andy commented on Harry Potter Bert Comment #31
... Bert commented on Harry Potter Andy Comment #32
... Chloe Cleoment commented on Harry Potter Andy Comment #33
... Chloe Cleoment commented on Harry Potter Bert Comment #33
... Robin Rood commented on Harry Potter Andy Comment #34
... Robin Rood commented on Harry Potter Bert Comment #34
... Andy commented on Star Trek Chloe Cleoment Comment #35
... Andy commented on Star Trek Robin Rood Comment #35
... Bert commented on Star Trek Chloe Cleoment Comment #36
... Bert commented on Star Trek Robin Rood Comment #36
... Chloe Cleoment commented on Star Trek Robin Rood Comment #37
... Robin Rood commented on Star Trek Chloe Cleoment Comment #38
... Andy commented on Star Trek Chloe Cleoment Comment #39
... Andy commented on Star Trek Robin Rood Comment #39
... Bert commented on Star Trek Chloe Cleoment Comment #40
... Bert commented on Star Trek Robin Rood Comment #40
... Chloe Cleoment commented on Star Trek Robin Rood Comment #41
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Andy Comment #42
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Bert Comment #42
... Andy commented on Hitchhiker's Guide to the Galaxy Bert Comment #43
... Bert commented on Hitchhiker's Guide to the Galaxy Andy Comment #44
... Chloe Cleoment commented on Hitchhiker's Guide to the Galaxy Andy Comment #45
... Chloe Cleoment commented on Hitchhiker's Guide to the Galaxy Bert Comment #45
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Andy Comment #46
... Robin Rood commented on Hitchhiker's Guide to the Galaxy Bert Comment #46
... Andy commented on Hitchhiker's Guide to the Galaxy Bert Comment #47
... Bert commented on Hitchhiker's Guide to the Galaxy Andy Comment #48
... Chloe Cleoment commented on Harry Potter Andy Comment #49
... Chloe Cleoment commented on Harry Potter Bert Comment #49
... Robin Rood commented on Harry Potter Andy Comment #50
... Robin Rood commented on Harry Potter Bert Comment #50
... Andy commented on Harry Potter Bert Comment #51
... Bert commented on Harry Potter Andy Comment #52
... Chloe Cleoment commented on Harry Potter Andy Comment #53
... Chloe Cleoment commented on Harry Potter Bert Comment #53
... Robin Rood commented on Harry Potter Andy Comment #54
... Robin Rood commented on Harry Potter Bert Comment #54
============================ ============================================================== ================ ============= ====== =====================
Class reference¶
- class lino.modlib.notify.Message¶
The Django model that represents a notification message.
- subject¶
The subject of this message. See Subject and body of a notification message.
- body¶
The body of this message. See Subject and body of a notification message.
- user¶
The recipient of this message. The site user to whom this message is to be delivered.
If this is empty, then it is a broadcast notification.
- owner¶
The owner of this message. Expresses what this message is about.
This is a generic foreign key. If this is empty, the message is said to have no owner.
- message_type¶
- reply_to¶
The comment to which a reply to this message would reply.
An email notification for this message will have this information in its reply-to header.
This is a dummy field unless the
lino.modlib.comments
plugin is installed.
- created¶
Timestamp of when this message has been emitted.
- sent¶
Timestamp of when this message has been sent via email to its recipient.
- seen¶
Timestamp of when the recipient of this message has marked it as seen.
- emit_notification(cls, ar, owner, message_type, msg_func, recipients)¶
Emit a notification message to each of the given recipients, respecting their individual user settings.
This is a class method that creates zero, one or several database rows.
recipients is an iterable of (user, mail_mode) tuples. Duplicate items, items with user being None and items having
mail_mode
set tosilent
are removed.msg_func is a callable expected to return either None or a tuple (subject, body). It is called for each recipient after having activated the recipient’s language, so that any translatable text will be translated to the user’s language.
The emitting user does not get notified unless they have
User.notify_myself
is set.
- create_message(cls, user, owner=None, **kwargs)¶
Create a message unless that user has already been notified about that object.
- send_summary_emails(cls, mm)¶
Send summary emails for all pending notifications with the given mail_mode mm.
- send_browser_message_for_all_users(self, user)¶
Send_message to all connected users
- send_browser_message(self, user)¶
Send_message to the user’s browser
- class lino.modlib.notify.Messages¶
Base for all tables of messages.
- class lino.modlib.notify.AllMessages(Messages)¶
The gobal list of all messages.
- class lino.modlib.notify.MyMessages(Messages)¶
Shows messages emitted to me.
Push subscriptions¶
- class lino.modlib.notify.Subscription¶
The Django model that represents a push subscription.
Loosely inspired by django-webpush.
- user¶
- lang¶
- userAgent¶
- endpoint¶
- p256dh¶
- auth¶
Change notifiers¶
- class lino.modlib.notify.ChangeNotifier¶
Model mixin for things that emit notifications to a list of observers (or “watchers”) when an instance is modified.
- add_change_watcher(self, user)¶
Parameters:
- User:
The user that will be linked to this object as a change watcher.
- get_change_subject(self, ar, cw)¶
Returns the subject text of the notification message to emit.
The default implementation returns a message of style “{user} modified|created {object}” .
Returning None or an empty string means to suppress notification.
- get_change_body(self, ar, cw)¶
Return the body text of the notification message to emit.
The default implementation returns a message “{user} created {what}” or “{user} modified {what}” followed by a summary of the changes.
For tested code snippets see See The get_change_body() method.
- get_change_info(self, ar, cw)¶
Return a list of HTML elements to be inserted into the body.
Removed since 20230822.
This is called by
get_change_body()
. Subclasses can override this. Usage examplelino_xl.lib.notes.models.Note
- get_change_owner(self)¶
Return the owner of the notification to emit.
The “owner” is “the database object we are talking about” and decides who is observing this object.
Notifying actions¶
A notifying action is an action that pops up a dialog window with at least three fields “Summary”, “Description” and a checkbox “Don’t notify others” to optionally suppress notification.
Screenshot of a notifying action:
- class lino.modlib.notify.NotifyingAction¶
Mixin for notifying actions.
Dialog fields:
- notify_subject¶
- notify_body¶
- notify_silent¶
- get_notify_subject(self, ar, obj)¶
Return the default value of the notify_subject field.
- get_notify_body(self, ar, obj)¶
Return the default value of the notify_body field.
- get_notify_owner(self, ar, obj)¶
Expected to return the
owner lino.modlib.notify.Message.owner>
of the message.The default returns None.
ar is the action request, obj the object on which the action is running,
- get_notify_recipients(self, ar, obj)¶
Yield a list of users to be notified.
ar is the action request, obj the object on which the action is running,
A NotifyingAction
is a dialog action that potentially sends a
notification. It has three dialog fields (“subject”, “body” and a checkbox
“silent”). You can have non-dialog actions (or actions with some other dialog
than a simple subject and body) which build a custom subject and body and emit a
notification. If the emitting object also has a method
emit_system_note()
, then this is being called as well.
Plugin settings¶
This plugin adds the following settings, which a server administrator can
configure in the settings.py
.
- notify.remove_after¶
Automatically remove notification messages after x days.
Default value is 14 days. Set this to None or 0 to deactivate cleanup and keep messages forever.
- notify.keep_unseen¶
Whether to keep unseen messages when removing old messages according to
remove_after
.In normal operation this should be True, but e.g. after a flood of messages during experimental phases we might want to get rid of them automatically.
- notify.mark_seen_when_sent¶
When this is True, Lino marks notification messages as seen when they have been sent via email.
- notify.use_push_api¶
Whether to enable desktop notifications using webpush.
In a production server it is mandatory to set your own vapid credentials:
- notify.vapid_private_key¶
The private VAPID key of this site.
- notify.vapid_public_key¶
The public VAPID key of this site.
- notify.vapid_admin_email¶
The VAPID contact address of this site.
>>> from django.conf import settings
>>> from lino.core.utils import is_devserver
>>> # import sys ; sys.argv
>>> is_devserver()
True
Utility functions¶
- lino.modlib.notify.send_pending_emails_often()¶
- lino.modlib.notify.send_pending_emails_daily()¶
- lino.modlib.notify.clear_seen_messages()¶
Daily task which deletes messages older than
remove_after
hours.
Choicelists¶
Actions¶
- class lino.modlib.notify.MarkSeen¶
Mark this message as seen.
- class lino.modlib.notify.MarkAllSeen¶
Mark all messages as seen.
- class lino.modlib.notify.ClearSeen¶
Mark this message as not yet seen.
Templates used by this plugin¶
- notify/body.eml¶
A Jinja template used for generating the body of the email when sending a message per email to its recipient.
Available context variables:
obj
– TheMessage
instance being sent.E
– The html namespaceetgen.html
rt
– The runtime APIlino.api.rt
ar
– The action request which caused the message. aBaseRequest
instance.