Package: openwisp-notifications
OpenWISP Notificationsprovides email and web notifications forOpenWISP.Its main goal is to allow the other OpenWISP modules to notify users about
meaningful events that happen in their network.For a more complete overview of the OpenWISP modules and architecture,
see theOpenWISP Architecture Overview.Table of Contents:Available featuresInstallation instructionsInstall stable version from pypiInstall development versionInstalling for developmentSetup (integrate into an existing Django project)Sending notificationsAdditionalnotifykeyword argumentsWeb NotificationsNotification WidgetNotification ToastsEmail NotificationsNotification CacheCache invalidationNotification TypesDefiningmessage_templateRegistering / Unregistering Notification Typesregister_notification_typeunregister_notification_typePassing extra data to notificationsNotification PreferencesDeleting Notification PreferencesSilencing notifications for specific objects temporarily or permanentlyScheduled deletion of notificationsSettingsOPENWISP_NOTIFICATIONS_HOSTOPENWISP_NOTIFICATIONS_SOUNDOPENWISP_NOTIFICATIONS_CACHE_TIMEOUTOPENWISP_NOTIFICATIONS_IGNORE_ENABLED_ADMINOPENWISP_NOTIFICATIONS_POPULATE_PREFERENCES_ON_MIGRATEOPENWISP_NOTIFICATIONS_NOTIFICATION_STORM_PREVENTIONExceptionsREST APILive documentationBrowsable web interfaceAuthenticationPaginationList of endpointsList user’s notificationsMark all user’s notifications as readGet notification detailsMark a notification readDelete a notificationList user’s notification settingGet notification setting detailsUpdate notification setting detailsList user’s object notification settingGet object notification setting detailsCreate object notification settingDelete object notification settingManagement Commandspopulate_notification_preferencescreate_notificationExtending openwisp-notifications1. Initialize your custom module2. Installopenwisp-notifications3. AddEXTENDED_APPS4. Addopenwisp_utils.staticfiles.DependencyFinder5. Addopenwisp_utils.loaders.DependencyLoader6. Inherit the AppConfig class7. Create your custom models8. Add swapper configurations9. Create database migrations10. Create your custom admin1. Monkey patching2. Inheriting admin classes11. Create root URL configuration12. Create root routing configuration13. Create celery.py14. Import Celery Tasks15. Register Template Tags16. Register Notification Types17. Import the automated testsOther base classes that can be inherited and extendedAPI viewsWeb Socket ConsumersContributingLicenseSupportAttributionsIconsSoundAvailable featuresSending notificationsWeb notificationsEmail notificationsNotification typesRegistering new notification typesUser notification preferencesSilencing notifications for specific objects temporarily or permanentlyAutomatic cleanup of old notificationsConfigurable host for API endpointsInstallation instructionsInstall stable version from pypiInstall from pypi:pipinstallopenwisp-notificationsInstall development versionInstall tarball:pipinstallhttps://github.com/openwisp/openwisp-notifications/tarball/masterAlternatively, you can install via pip using git:pipinstall-egit+git://github.com/openwisp/openwisp-notifications#egg=openwisp_notificationsInstalling for developmentWe use Redis as celery broker (you can use a different broker if you want).
The recommended way for development is running it using Docker so you will need toinstall docker and docker-composebeforehand.In case you prefer not to use Docker you caninstall Redis from your repositories, but keep in mind that
the version packaged by your distribution may be different.Install SQLite:sudoaptinstallsqlite3libsqlite3-devopenssllibssl-devFork and clone the forked repository:gitclonegit://github.com/<your_fork>/openwisp-notificationsNavigate into the cloned repository:cdopenwisp-notifications/Setup and activate a virtual-environment. (we’ll be usingvirtualenv)python-mvirtualenvenvsourceenv/bin/activateUpgrade the following base python packages:pipinstall-UpipwheelsetuptoolsInstall development dependencies:pipinstall-e.pipinstall-rrequirements-test.txtnpminstall-gjslintstylelintStart Redis using docker-compose:docker-composeup-dCreate a database:cdtests/./manage.pymigrate./manage.pycreatesuperuserLaunch the development server:./manage.pyrunserverYou can access the admin interface athttp://127.0.0.1:8000/admin/.Run celery  worker (separate terminal window is needed):# (cd tests)celery-Aopenwisp2worker-linfoRun tests with:# run qa checks./run-qa-checks# standard tests./runtests.py# tests for the sample appSAMPLE_APP=1./runtests.py# If you running tests on PROD environment./runtests.py--excludeskip_prodWhen running the last line of the previous example, the environment variableSAMPLE_APPactivates
the sample app in/tests/openwisp2/which is a simple django app that extendsopenwisp-notificationswith the sole purpose of testing its extensibility, for more information regarding this concept,
read the following section.Setup (integrate into an existing Django project)INSTALLED_APPSinsettings.pyshould look like the following:INSTALLED_APPS=['django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','django.contrib.sites','django_extensions','allauth','allauth.account','allauth.socialaccount',# rest framework'rest_framework','rest_framework.authtoken','drf_yasg','django_filters','openwisp_users',# notifications module'openwisp_notifications',# add openwisp theme# (must be loaded here)'openwisp_utils.admin_theme','django.contrib.admin',# channels'channels',]Note:openwisp_utils.admin_themeanddjango.contrib.adminshould always
followopenwisp_notificationsinINSTALLED_APPSas shown in the example above.
It might result in undesired behavior otherwise, e.g. notification bell not being
shown on admin site.Addnotification_api_settingscontext processor:TEMPLATES=[{# ...'OPTIONS':{# ...'context_processors':[# ...'openwisp_notifications.context_processors.notification_api_settings',# ...],},},]urls.py:fromdjango.contribimportadminfromdjango.urlsimportinclude,pathfromdjango.contrib.staticfiles.urlsimportstaticfiles_urlpatternsurlpatterns=[path('admin/',admin.site.urls),path('api/v1/',include(('openwisp_users.api.urls','users'),namespace='users')),path('',include('openwisp_notifications.urls',namespace='notifications')),]urlpatterns+=staticfiles_urlpatterns()Add routes for websockets:# In yourproject/asgi.pyfromchannels.authimportAuthMiddlewareStackfromchannels.routingimportProtocolTypeRouter,URLRouterfromdjango.core.asgiimportget_asgi_applicationfromopenwisp_notifications.websockets.routingimportget_routesapplication=ProtocolTypeRouter({'websocket':AuthMiddlewareStack(URLRouter(get_routes()))})Configure caching (you may use a different cache storage if you want):CACHES={'default':{'BACKEND':'django_redis.cache.RedisCache','LOCATION':'redis://localhost/0','OPTIONS':{'CLIENT_CLASS':'django_redis.client.DefaultClient',}}}SESSION_ENGINE='django.contrib.sessions.backends.cache'SESSION_CACHE_ALIAS='default'Configure celery:# Here we are showing how to configure celery with Redis but you can# use other brokers if you want, consult the celery docsCELERY_BROKER_URL='redis://localhost/1'Configure celery beat:CELERY_BEAT_SCHEDULE={'delete_old_notifications':{'task':'openwisp_notifications.tasks.delete_old_notifications','schedule':timedelta(days=1),'args':(90,),},}Note: You will only need to addCELERY_BEAT_SCHEDULEsetting if you want
automatic deletion of old notifications. Please readScheduled deletion of notificationssection to learn more about this feature.If you decide to use redis (as shown in these examples), make sure the python
dependencies are installed in your system:pipinstallredisdjango-redisConfigureASGI_APPLICATION:ASGI_APPLICATION='yourproject.asgi.application'Configure channel layers (you may use adifferent channel layer):CHANNEL_LAYERS={'default':{'BACKEND':'channels_redis.core.RedisChannelLayer','CONFIG':{'hosts':['redis://localhost/7'],},},}While development, you can configure it to localhost as shown below:INTERNAL_IPS=['127.0.0.1']Run migrations./manage.pymigrateNote: Running migrations is also required for creatingnotification settingsapart from creating database schema.Sending notificationsNotifications can be created using thenotifysignal. Eg:fromdjango.contrib.authimportget_user_modelfromswapperimportload_modelfromopenwisp_notifications.signalsimportnotifyUser=get_user_model()Group=load_model('openwisp_users','Group')admin=User.objects.get(email='admin@admin.com')operators=Group.objects.get(name='Operator')notify.send(sender=admin,recipient=operators,description="Test Notification",verb="Test Notification",email_subject='Test Email Subject',url='https://localhost:8000/admin',)The above code snippet creates and sends a notification to all users belonging to theOperatorsgroup if they have opted-in to receive notifications. Non-superusers receive notifications
only for organizations which they are a member of.Note: If recipient is not provided, it defaults to all superusers. If the target is provided, users
of same organization of the target object are added to the list of recipients given that they have staff
status and opted-in to receive notifications.The complete syntax fornotifyis:notify.send(actor,recipient,verb,action_object,target,level,description,**kwargs)Note: Sinceopenwisp-notificationsusesdjango-notificationsunder the hood, usage of thenotify signalhas been kept unaffected to maintain consistency withdjango-notifications.
You can learn more about accepted parameters fromdjango-notifications documentation.Additionalnotifykeyword argumentsParameterDescriptionemail_subjectSets subject of email notification to be sent.Defaults to the notification message.urlAdds a URL in the email text, eg:For more information see <url>.Defaults toNone, meaning the above message would
not be added to the email text.typeSet values of other parameters based on registerednotification typesDefaults toNonemeaning you need to provide other arguments.Web NotificationsOpenwisp Notificationssend a web notification to the recipients through
django’s admin site. Following are the components which allows browsing
web notifications:Notification WidgetA javascript widget has been added to make consuming notifications easy for users.
The notification widget provides following features:A minimalistic UI to help getting things done quickly.Dynamically loading notifications with infinite scrolling to prevent unnecessary
network requests.Option to filter unread notifications.Option to mark all notifications as read on a single click.Notification ToastsA notification toast delivers notifications at real-time. This allows
users to read notifications without even opening the notification widget.
A notification bell is also played to alert each time a notification is
displayed through notification toast.Email NotificationsAlong with web notificationsOpenWISP Notificationsalso sends email notifications
leveraging theopenwisp-utils send_email feature.Notification CacheIn a typical OpenWISP installation,actor,action_objectandtargetobjects are same
for a number of notifications. To optimize database queries, these objects are cached usingDjango’s cache framework.
The cached values are updated automatically to reflect actual data from database. You can control
the duration of caching these objects usingOPENWISP_NOTIFICATIONS_CACHE_TIMEOUT setting.Cache invalidationThe functionregister_notification_cache_updatecan be used to register a signal of a model which is being used as anactor,action_objectandtargetobjects. As these values are cached for the optimization purpose so their cached
values are need to be changed when they are changed. You can register any signal you want which will delete the cached value.
To register a signal you need to include following code in yourapps.py.fromdjango.db.models.signalsimportpost_savefromswapperimportload_modeldefready(self):super().ready()# Include lines after this inside# ready function of you app config classfromopenwisp_notifications.handlersimportregister_notification_cache_updatemodel=load_model('app_name','model_name')register_notification_cache_update(model,post_save,dispatch_uid="myapp_mymodel_notification_cache_invalidation")Note: You need to importregister_notification_cache_updateinside thereadyfunction or
you can define another funtion to register signals which will be called inreadyand then it will be
imported in this function. Alsodispatch_uidis unique identifier of a signal. You can pass any
value you want but it needs to be unique. For more details readpreventing duplicate signals section of Django documentationNotification TypesOpenWISP Notificationssimplifies configuring individual notification by
using notification types. You can think of a notification type as a template
for notifications.These properties can be configured for each notification type:PropertyDescriptionlevelSetslevelattribute of the notification.verbSetsverbattribute of the notification.verbose_nameSets display name of notification type.messageSetsmessageattribute of the notification.email_subjectSets subject of the email notification.message_templatePath to file having template for message of the notification.email_notificationSets preference for email notifications. Defaults toTrue.web_notificationSets preference for web notifications. Defaults toTrue.Note: A notification type configuration should contain atleast one ofmessageormessage_templatesettings. If both of them are present,messageis given preference overmessage_template.Definingmessage_templateYou can either extend default message template or write your own markdown formatted message template
from scratch. An example to extend default message template is shown below.# In templates/your_notifications/your_message_template.md{%extends'openwisp_notifications/default_message.md'%}{%blockbody%}[{{notification.target}}]({{notification.target_link}}) has malfunctioned.{%endblockbody%}Note: You can access all attributes of the notification usingnotificationvariables in your message
template as shown above. Additional attributesactor_link,action_linkandtarget_linkare
also available for providing hyperlinks to respective object.Note: After writing code for registering or unregistering notification types, it is recommended to run
database migrations to createnotification settlingsfor these notification types.Registering / Unregistering Notification TypesOpenWISP Notificationsprovides registering and unregistering notifications through utility functionsopenwisp_notifications.types.register_notification_typeandopenwisp_notifications.types.unregister_notification_type.
Using these functions you can register or unregister notification types from your code.register_notification_typeThis function is used to register a new notification type from your code.Syntax:register_notification_type(type_name,type_config,models)ParameterDescriptiontype_nameAstrdefining name of the notification type.type_configAdictdefining configuration of the notification type.modelsAn optionallistof models that can be associated with
the notification type.An example usage has been shown below.fromopenwisp_notifications.typesimportregister_notification_typefromdjango.contrib.authimportget_user_modelUser=get_user_model()# Define configuration of your notification typecustom_type={'level':'info','verb':'added','verbose_name':'device added','message':'[{notification.target}]({notification.target_link}) was{notification.verb}at{notification.timestamp}','email_subject':'[{site.name}] A device has been added','web_notification':True,'email_notification':True,}# Register your custom notification typeregister_notification_type('custom_type',custom_type,models=[User])Note: It will raiseImproperlyConfiguredexception if a notification type is already registered
with same name(not to be confused withverbose_name).Note: You can usesiteandnotificationvariables while definingmessageandemail_subjectconfiguration of notification type. They refer to objects ofdjango.contrib.sites.models.Siteandopenwisp_notifications.models.Notificationrespectively.
This allows you to use any of their attributes in your configuration. Similarly tomessage_template,messageproperty can also be formatted using markdown.unregister_notification_typeThis function is used to unregister a notification type from anywhere in your code.Syntax:unregister_notification_type(type_name)ParameterDescriptiontype_nameAstrdefining name of the notification type.An example usage is shown below.fromopenwisp_notifications.typesimportunregister_notification_type# Unregister previously registered notification typeunregister_notification_type('custom type')Note: It will raiseImproperlyConfiguredexception if the concerned
notification type is not registered.Passing extra data to notificationsIf needed, additional data, not known beforehand, can be included in the notification message.A perfect example for this case is an error notification, the error message will vary
depending on what has happened, so we cannot know until the notification is generated.Here’s how to do it:fromopenwisp_notifications.typesimportregister_notification_typeregister_notification_type('error_type',{'verbose_name':'Error','level':'error','verb':'error','message':'Error:{error}','email_subject':'Error subject:{error}',})Then in the application code:fromopenwisp_notifications.signalsimportnotifytry:operation_which_can_fail()exceptExceptionaserror:notify.send(type='error_type',sender=sender,error=str(error))Note: It is recommended that all notification types are registered or
unregistered inreadymethod of your Django application’sAppConfig.Notification PreferencesOpenWISP Notificationsallows users to select their preferred way of receiving notifications.
Users can choose from web or email notifications. These settings have been categorized
over notification type and organization, therefore allowing users to only receive notifications
from selected organization or notification type.Notification settings are automatically created for all notification types and organizations for all users.
While superusers can add or delete notification settings for everyone, staff users can only modify their
preferred ways for receiving notifications. With provided functionality, users can choose to receive both
web and email notifications or only web notifications. Users can also stop receiving notifications
by disabling both web and email option for a notification setting.Note: If a user has not configured their email or web preference for a particular notification setting,
thenemail_notificationorweb_notificationoption of concerned notification type will be used
respectively.Deleting Notification PreferencesDeleting the notification preferences is an advanced option. Users should turn off web and email
notifications instead of deleting notification preferences. Deleted notification preferences
may be re-created automatically if the system needs it.Silencing notifications for specific objects temporarily or permanentlyOpenWISP Notificationsallows users to silence all notifications generated by
specific objects they are not interested in for a desired period of time or even permanently,
while other users will keep receiving notifications normally.Using the widget on an object’s admin change form, a user can disable all notifications
generated by that object for a day, week, month or permanently.Note: This feature requires configuring“OPENWISP_NOTIFICATIONS_IGNORE_ENABLED_ADMIN”to enable the widget in the admin section of the required models.Scheduled deletion of notificationsOpenWISP Notificationsprovides a celery task to automatically delete
notifications older than a pre-configured number of days. In order to run this
task periodically, you will need to configureCELERY_BEAT_SCHEDULEsetting as shown
insetup instructions.The celery task takes only one argument, i.e. number of days. You can provide
any number of days inargskey while configuringCELERY_BEAT_SCHEDULEsetting.E.g., if you want notifications older than 10 days to get deleted automatically,
then configureCELERY_BEAT_SCHEDULEas follows:CELERY_BEAT_SCHEDULE={'delete_old_notifications':{'task':'openwisp_notifications.tasks.delete_old_notifications','schedule':timedelta(days=1),'args':(10,),# Here we have defined 10 instead of 90 as shown in setup instructions},}Please refer to“Periodic Tasks” section of Celery’s documentationto learn more.SettingsOPENWISP_NOTIFICATIONS_HOSTtypestrdefaultAny domain defined inALLOWED_HOSTThis setting defines the domain at which API and Web Socket communicate for
working of notification widget.Note: You don’t need to configure this setting if you
don’t host your API endpoints on a different sub-domain.If your root domain isexample.comand API and Web Socket are hosted atapi.example.com, then configure setting as follows:OPENWISP_NOTIFICATIONS_HOST='https://api.example.com'This feature requires you to allowCORSon your server. We usedjango-cors-headersmodule to easily setup CORS headers.
Please referdjango-core-headers’ setup documentation.Configuredjango-cors-headerssettings as follows:CORS_ALLOW_CREDENTIALS=TrueCORS_ORIGIN_WHITELIST=['https://www.example.com']Configure Django’s settings as follows:SESSION_COOKIE_DOMAIN='example.com'CSRF_COOKIE_DOMAIN='example.com'Please refer toDjango’s settings documentationfor more information onSESSION_COOKIE_DOMAINandCSRF_COOKIE_DOMAINsettings.OPENWISP_NOTIFICATIONS_SOUNDtypestrdefaultnotification_bell.mp3This setting defines notification sound to be played when notification is received
in real-time on admin site.Provide a relative path (hosted on your webserver) to audio file as show below.OPENWISP_NOTIFICATIONS_SOUND='your-appname/audio/notification.mp3'OPENWISP_NOTIFICATIONS_CACHE_TIMEOUTtypeintdefault172800(2 days, in seconds)It sets the number of seconds the notification contents should be stored in the cache.
If you want cached notification content to never expire, then set it toNone.
Set it to0if you don’t want to store notification contents in cache at all.OPENWISP_NOTIFICATIONS_IGNORE_ENABLED_ADMINtypelistdefault[]This setting enables the widget which allows users tosilence notifications for specific objects temporarily or permanently.in the change page of the specifiedModelAdminclasses.E.g., if you want to enable the widget for objects ofopenwisp_users.models.Usermodel, then configure the setting as following:OPENWISP_NOTIFICATIONS_IGNORE_ENABLED_ADMIN=['openwisp_users.admin.UserAdmin']OPENWISP_NOTIFICATIONS_POPULATE_PREFERENCES_ON_MIGRATEtypebooldefaultTrueThis setting allows to disable creatingnotification preferenceson running migrations.OPENWISP_NOTIFICATIONS_NOTIFICATION_STORM_PREVENTIONWhen the system starts creating a lot of notifications because of a
general network outage (e.g.: a power outage, a global misconfiguration),
the notification storm prevention mechanism avoids the constant displaying
of new notification alerts as well as their sound, only the notification
counter will continue updating periodically, although it won’t emit any
sound or create any other visual element until the
notification storm is over.This setting allows tweaking how this mechanism works.The default configuration is as follows:OPENWISP_NOTIFICATIONS_NOTIFICATION_STORM_PREVENTION={# Time period for tracking burst of notifications (in seconds)'short_term_time_period':10,# Number of notifications considered as a notification burst'short_term_notification_count':6,# Time period for tracking notifications in long time interval (in seconds)'long_term_time_period':180,# Number of notifications in long time interval to be considered as a notification storm'long_term_notification_count':30,# Initial time for which notification updates should be skipped (in seconds)'initial_backoff':1,# Time by which skipping of notification updates should be increased (in seconds)'backoff_increment':1,# Maximum interval after which the notification widget should get updated (in seconds)'max_allowed_backoff':15,}ExceptionsNotificationRenderExceptionopenwisp_notifications.exceptions.NotificationRenderExceptionRaised when notification properties(emailormessage) cannot be rendered from
concernednotification type. It sub-classesExceptionclass.It can be raised due to accessing non-existing keys like missing related objects
inemailormessagesetting of concernednotification type.REST APILive documentationA general live API documentation (following the OpenAPI specification) is available at/api/v1/docs/.Browsable web interfaceAdditionally, opening any of the endpointslisted belowdirectly in the browser will show thebrowsable API interface of Django-REST-Framework,
which makes it even easier to find out the details of each endpoint.AuthenticationSee openwisp-users:authenticating with the user token.When browsing the API via theLive documentationor theBrowsable web interface, you can use
the session authentication by logging in the django admin.PaginationThelistendpoint support thepage_sizeparameter that allows paginating
the results in conjunction with thepageparameter.GET /api/v1/notifications/notification/?page_size=10
GET /api/v1/notifications/notification/?page_size=10&page=2List of endpointsSince the detailed explanation is contained in theLive documentationand in theBrowsable web pageof each endpoint,
here we’ll provide just a list of the available endpoints,
for further information please open the URL of the endpoint in your browser.List user’s notificationsGET /api/v1/notifications/notification/Mark all user’s notifications as readPOST /api/v1/notifications/notification/read/Get notification detailsGET /api/v1/notifications/notification/{pk}/Mark a notification readPATCH /api/v1/notifications/notification/{pk}/Delete a notificationDELETE /api/v1/notifications/notification/{pk}/List user’s notification settingGET /api/v1/notifications/notification/user-setting/Get notification setting detailsGET /api/v1/notifications/notification/user-setting/{pk}/Update notification setting detailsPATCH /api/v1/notifications/notification/user-setting/{pk}/List user’s object notification settingGET /api/v1/notifications/notification/ignore/Get object notification setting detailsGET /api/v1/notifications/notification/ignore/{app_label}/{model_name}/{object_id}/Create object notification settingPUT /api/v1/notifications/notification/ignore/{app_label}/{model_name}/{object_id}/Delete object notification settingDELETE /api/v1/notifications/notification/ignore/{app_label}/{model_name}/{object_id}/Management Commandspopulate_notification_preferencesThis command will populate notification preferences for all users for organizations
they are member of.Example usage:# cd tests/./manage.pypopulate_notification_preferencesNote: Before running this command make sure that the celery broker is
running andreachableby celery workers.create_notificationThis command will create a dummy notification withdefaultnotification type
for the members ofdefaultorganization.
This command is primarily provided for the sole purpose of testing notification
in development only.Example usage:# cd tests/./manage.pycreate_notificationExtending openwisp-notificationsOne of the core values of the OpenWISP project isSoftware Reusability,
for this reasonOpenWISP Notificationsprovides a set of base classes which can be imported, extended
and reused to create derivative apps.In order to implement your custom version ofopenwisp-notifications, you need to perform the steps
described in the rest of this section.When in doubt, the code intest projectandsample_notificationswill guide you in the correct direction: just replicate and adapt that code to get a basic derivative ofopenwisp-notificationsworking.Premise: if you plan on using a customized version of this module, we suggest to start with it since
the beginning, because migrating your data from the default module to your extended version may be time
consuming.1. Initialize your custom moduleThe first thing you need to do in order to extendopenwisp-notificationsis create a new django app which
will contain your custom version of thatopenwisp-notificationsapp.A django app is nothing more than apython package(a directory of python scripts), in the following examples we’ll call this django app asmynotificationsbut you can name it how you want:django-adminstartappmynotificationsKeep in mind that the command mentioned above must be called from a directory which is available in yourPYTHON_PATHso that you can then import
the result into your project.Now you need to addmynotificationstoINSTALLED_APPSin yoursettings.py, ensuring also thatopenwisp_notificationshas been removed:INSTALLED_APPS=[# ... other apps ...# 'openwisp_notifications',        <-- comment out or delete this line'mynotifications',]For more information about how to work with django projects and django apps, please refer to thedjango documentation.2. Installopenwisp-notificationsInstall (and add to the requirement of your project)openwisp-notifications:pipinstall-Uhttps://github.com/openwisp/openwisp-notifications/tarball/master3. AddEXTENDED_APPSAdd the following to yoursettings.py:EXTENDED_APPS=['openwisp_notifications']4. Addopenwisp_utils.staticfiles.DependencyFinderAddopenwisp_utils.staticfiles.DependencyFindertoSTATICFILES_FINDERSin yoursettings.py:STATICFILES_FINDERS=['django.contrib.staticfiles.finders.FileSystemFinder','django.contrib.staticfiles.finders.AppDirectoriesFinder','openwisp_utils.staticfiles.DependencyFinder',]5. Addopenwisp_utils.loaders.DependencyLoaderAddopenwisp_utils.loaders.DependencyLoadertoTEMPLATESin yoursettings.py:TEMPLATES=[{'BACKEND':'django.template.backends.django.DjangoTemplates','OPTIONS':{'loaders':['django.template.loaders.filesystem.Loader','django.template.loaders.app_directories.Loader','openwisp_utils.loaders.DependencyLoader',],'context_processors':['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},}]6. Inherit the AppConfig classPlease refer to the following files in the sample app of the test project:sample_notifications/__init__.py.sample_notifications/apps.py.For more information regarding the concept ofAppConfigplease refer to the“Applications” section in the django documentation.7. Create your custom modelsFor the purpose of showing an example, we added a simple “details” field to themodels of the sample app in the test project.You can add fields in a similar way in yourmodels.pyfile.Note: For doubts regarding how to use, extend or develop models please refer to
the“Models” section in the django documentation.8. Add swapper configurationsAdd the following to yoursettings.py:# Setting models for swapper moduleOPENWISP_NOTIFICATIONS_NOTIFICATION_MODEL='mynotifications.Notification'OPENWISP_NOTIFICATIONS_NOTIFICATIONSETTING_MODEL='mynotifications.NotificationSetting'OPENWISP_NOTIFICATIONS_IGNOREOBJECTNOTIFICATION_MODEL='mynotifications.IgnoreObjectNotification'9. Create database migrationsCreate and apply database migrations:./manage.py makemigrations
./manage.py migrateFor more information, refer to the“Migrations” section in the django documentation.10. Create your custom adminRefer to theadmin.py file of the sample app.To introduce changes to the admin, you can do it in two main ways which are described below.Note: For more information regarding how the django admin works, or how it can be customized,
please refer to“The django admin site” section in the django documentation.1. Monkey patchingIf the changes you need to add are relatively small, you can resort to monkey patching.For example:fromopenwisp_notifications.adminimportNotificationSettingInlineNotificationSettingInline.list_display.insert(1,'my_custom_field')NotificationSettingInline.ordering=['-my_custom_field']2. Inheriting admin classesIf you need to introduce significant changes and/or you don’t want to resort to
monkey patching, you can proceed as follows:fromdjango.contribimportadminfromopenwisp_notifications.adminimport(NotificationSettingInlineasBaseNotificationSettingInline,)fromopenwisp_notifications.swapperimportload_modelNotificationSetting=load_model('NotificationSetting')admin.site.unregister(NotificationSettingAdmin)admin.site.unregister(NotificationSettingInline)@admin.register(NotificationSetting)classNotificationSettingInline(BaseNotificationSettingInline):# add your changes herepass11. Create root URL configurationPlease refer to theurls.pyfile in the test project.For more information about URL configuration in django, please refer to the“URL dispatcher” section in the django documentation.12. Create root routing configurationPlease refer to therouting.pyfile in the test project.For more information about URL configuration in django, please refer to the“Routing” section in the Channels documentation.13. Create celery.pyPlease refer to thecelery.pyfile in the test project.For more information about the usage of celery in django, please refer to the“First steps with Django” section in the celery documentation.14. Import Celery TasksAdd the following in your settings.py to import celery tasks fromopenwisp_notificationsapp.CELERY_IMPORTS=('openwisp_notifications.tasks',)15. Register Template TagsIf you need to use template tags ofopenwisp_notifications, you will need to register as shown in“templatetags/notification_tags.py” of sample_notifications.For more information about template tags in django, please refer to the“Custom template tags and filters” section in the django documentation.16. Register Notification TypesYou can register notification types as shown in thesection for registering notification types.A reference for registering a notification type is also provided insample_notifications/apps.py.
The registered notification type ofsample_notificationsapp is used for creating notifications
when an object ofTestAppmodel is created. You can usesample_notifications/models.pyas reference for your implementation.17. Import the automated testsWhen developing a custom application based on this module, it’s a good idea to import and run the base tests
too, so that you can be sure the changes you’re introducing are not breaking some of the existing feature
of openwisp-notifications.In case you need to add breaking changes, you can overwrite the tests defined in the base classes to test
your own behavior.See thetests of the sample_notificationsto find out how to do this.Note: Some tests will fail iftemplatetagsandadmin/base.htmlare not configured properly.
See preceeding sections to configure them properly.Other base classes that can be inherited and extendedThe following steps are not required and are intended for more advanced customization.API viewsThe API view classes can be extended into other django applications as well. Note
that it is not required for extending openwisp-notifications to your app and this change
is required only if you plan to make changes to the API views.Create a view file as done insample_notifications/views.pyFor more information regarding Django REST Framework API views, please refer to the“Generic views” section in the Django REST Framework documentation.Web Socket ConsumersThe Web Socket Consumer classes can be extended into other django applications as well. Note
that it is not required for extending openwisp-notifications to your app and this change
is required only if you plan to make changes to the consumers.Create a consumer file as done insample_notifications/consumers.pyFor more information regarding Channels’ Consumers, please refer to the“Consumers” section in the Channels documentation.ContributingPlease read theOpenWISP contributing guidelines.LicenseSeeLICENSE.SupportSeeOpenWISP Support Channels.AttributionsIconsIconsused are taken fromFont Awesomeproject.LICENSE:https://fontawesome.com/licenseSoundNotification soundis taken fromNotification Sounds.LICENSE:Creative Commons Attribution license