diff --git a/combo/apps/notifications/models.py b/combo/apps/notifications/models.py index dd3941ed..e3bf7a27 100644 --- a/combo/apps/notifications/models.py +++ b/combo/apps/notifications/models.py @@ -27,6 +27,8 @@ from django.db.models.query import QuerySet from combo.data.models import CellBase from combo.data.library import register_cell_class +from combo.apps.pwa.models import PwaSettings + class NotificationQuerySet(QuerySet): def namespace(self, namespace): @@ -181,6 +183,8 @@ class NotificationsCell(CellBase): qs = Notification.objects.visible(user) extra_context['notifications'] = qs extra_context['new_notifications'] = qs.new() + pwa_settings = PwaSettings.singleton() + extra_context['push_notifications_enabled'] = pwa_settings.push_notifications return extra_context def get_badge(self, context): diff --git a/combo/apps/notifications/templates/combo/notificationscell.html b/combo/apps/notifications/templates/combo/notificationscell.html index 3df3ad84..549046e9 100644 --- a/combo/apps/notifications/templates/combo/notificationscell.html +++ b/combo/apps/notifications/templates/combo/notificationscell.html @@ -20,4 +20,37 @@
{% trans 'No notifications.' %}
{% endif %} + +{% if push_notifications_enabled %} + + + +{% endif %} + {% endblock %} diff --git a/combo/apps/pwa/manager_views.py b/combo/apps/pwa/manager_views.py index 8ea68829..f6b71e23 100644 --- a/combo/apps/pwa/manager_views.py +++ b/combo/apps/pwa/manager_views.py @@ -24,12 +24,13 @@ from django.views.generic import CreateView, UpdateView, DeleteView from combo.data.forms import get_page_choices from .models import PwaSettings, PwaNavigationEntry +from .forms import PwaSettingsForm class ManagerHomeView(UpdateView): template_name = 'combo/pwa/manager_home.html' model = PwaSettings - fields = '__all__' + form_class = PwaSettingsForm success_url = reverse_lazy('pwa-manager-homepage') def get_initial(self): diff --git a/combo/apps/pwa/models.py b/combo/apps/pwa/models.py index 355291a1..05e8703c 100644 --- a/combo/apps/pwa/models.py +++ b/combo/apps/pwa/models.py @@ -29,6 +29,8 @@ from django.utils.encoding import force_text, force_bytes from django.utils.six import BytesIO from django.utils.translation import ugettext_lazy as _ +from py_vapid import Vapid + from jsonfield import JSONField from combo.data.fields import RichTextField from combo import utils @@ -51,8 +53,24 @@ class PwaSettings(models.Model): default=_('You are currently offline.'), config_name='small') offline_retry_button = models.BooleanField(_('Include Retry Button'), default=True) + push_notifications = models.BooleanField( + verbose_name=_('Enable subscription to push notifications'), + default=False) + push_notifications_infos = JSONField(blank=True) last_update_timestamp = models.DateTimeField(auto_now=True) + def save(self, **kwargs): + if self.push_notifications and not self.push_notifications_infos: + # generate VAPID keys + vapid = Vapid() + vapid.generate_keys() + self.push_notifications_infos = { + 'private_key': vapid.private_pem(), + } + elif not self.push_notifications: + self.push_notifications_infos = {} + return super(PwaSettings, self).save(**kwargs) + @classmethod def singleton(cls): return cls.objects.first() or cls() diff --git a/combo/apps/pwa/signals.py b/combo/apps/pwa/signals.py index 2b7f2b3a..91f6391d 100644 --- a/combo/apps/pwa/signals.py +++ b/combo/apps/pwa/signals.py @@ -21,22 +21,29 @@ from django.conf import settings from django.db.models.signals import post_save from django.dispatch import receiver -try: - import pywebpush -except ImportError: - pywebpush = None +from py_vapid import Vapid +import pywebpush from combo.apps.notifications.models import Notification -from .models import PushSubscription +from .models import PushSubscription, PwaSettings @receiver(post_save, sender=Notification) def notification(sender, instance=None, created=False, **kwargs): - if not pywebpush: - return if not created: return + pwa_settings = PwaSettings.singleton() + if not pwa_settings.push_notifications: + return + if settings.PWA_VAPID_PRIVATE_KEY: # legacy + pwa_vapid_private_key = settings.PWA_VAPID_PRIVATE_KEY + else: + pwa_vapid_private_key = Vapid.from_pem(pwa_settings.push_notifications_infos['private_key'].encode('ascii')) + if settings.PWA_VAPID_CLAIMS: # legacy + claims = settings.PWA_VAPID_CLAIMS + else: + claims = {'sub': 'mailto:%s' % settings.DEFAULT_FROM_EMAIL} message = json.dumps({ 'summary': instance.summary, 'body': instance.body, @@ -48,8 +55,8 @@ def notification(sender, instance=None, created=False, **kwargs): pywebpush.webpush( subscription_info=subscription.subscription_info, data=message, - vapid_private_key=settings.PWA_VAPID_PRIVATE_KEY, - vapid_claims=settings.PWA_VAPID_CLAIMS + vapid_private_key=pwa_vapid_private_key, + vapid_claims=claims, ) except pywebpush.WebPushException as e: logger = logging.getLogger(__name__) diff --git a/combo/apps/pwa/templates/combo/service-worker-registration.js b/combo/apps/pwa/templates/combo/service-worker-registration.js index a9dbba1f..0dc27e68 100644 --- a/combo/apps/pwa/templates/combo/service-worker-registration.js +++ b/combo/apps/pwa/templates/combo/service-worker-registration.js @@ -1,4 +1,6 @@ -var applicationServerPublicKey = {% if pwa_vapid_publik_key %}'{{ pwa_vapid_publik_key }}'{% else %}null{% endif %}; +{% load combo %} + +var applicationServerPublicKey = {{ pwa_vapid_public_key|as_json|safe }}; var COMBO_PWA_USER_SUBSCRIPTION = false; function urlB64ToUint8Array(base64String) { diff --git a/combo/apps/pwa/templates/combo/service-worker.js b/combo/apps/pwa/templates/combo/service-worker.js index 92c6e317..47673bff 100644 --- a/combo/apps/pwa/templates/combo/service-worker.js +++ b/combo/apps/pwa/templates/combo/service-worker.js @@ -3,7 +3,7 @@ /* global self, caches, fetch, URL, Response */ 'use strict'; -const applicationServerPublicKey = {{ pwa_vapid_publik_key|as_json|safe }}; +const applicationServerPublicKey = {{ pwa_vapid_public_key|as_json|safe }}; function urlB64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); diff --git a/combo/apps/pwa/views.py b/combo/apps/pwa/views.py index b4c82e7b..09bac4fd 100644 --- a/combo/apps/pwa/views.py +++ b/combo/apps/pwa/views.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see