Skip to content

Commit

Permalink
[Fix #35] Updating webpush configuration for latest version of chrome
Browse files Browse the repository at this point in the history
  • Loading branch information
safwanrahman committed Mar 2, 2018
1 parent 5c9c517 commit aed8d52
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 45 deletions.
5 changes: 0 additions & 5 deletions webpush/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
from django.conf import settings

MANIFEST = {}
if hasattr(settings,'WEBPUSH_SETTINGS'):
MANIFEST["gcm_sender_id"] = settings.WEBPUSH_SETTINGS['GCM_ID']
12 changes: 5 additions & 7 deletions webpush/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from .models import Group, PushInformation, SubscriptionInfo



class WebPushForm(forms.Form):
group = forms.CharField(max_length=255, required=False)
status_type = forms.ChoiceField(choices=[
Expand All @@ -19,7 +18,7 @@ def save_or_delete(self, subscription, user, status_type, group_name):

if group_name:
group, created = Group.objects.get_or_create(name=group_name)
data["group"] = group
data["group"] = group

data["subscription"] = subscription

Expand All @@ -36,9 +35,8 @@ class SubscriptionForm(forms.ModelForm):

class Meta:
model = SubscriptionInfo
fields = ('browser', 'endpoint', 'auth', 'p256dh')

fields = ('endpoint', 'auth', 'p256dh')

def get_or_save(self, subscription_data):
subscription, created = SubscriptionInfo.objects.get_or_create(**subscription_data)
return subscription
def get_or_save(self):
subscription, created = SubscriptionInfo.objects.get_or_create(**self.cleaned_data)
return subscription
5 changes: 3 additions & 2 deletions webpush/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# Create your models here.


class Group(models.Model):
name = models.CharField(max_length=255, unique=True)

Expand All @@ -20,12 +21,12 @@ class PushInformation(models.Model):
subscription = models.ForeignKey(SubscriptionInfo, related_name='webpush_info')
group = models.ForeignKey(Group, related_name='webpush_info', blank=True, null=True)

def save(self, force_insert=False, force_update=False, using=None):
def save(self, *args, **kwargs):
# Check whether user or the group field is present
# At least one field should be present there
# Through from the functionality its not possible, just in case! ;)
if self.user or self.group:
super(PushInformation, self).save()
super(PushInformation, self).save(*args, **kwargs)
else:
raise FieldError('At least user or group should be present')

33 changes: 28 additions & 5 deletions webpush/static/webpush/webpush.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ window.addEventListener('load', function() {

function subscribe(reg) {
// Get the Subscription or register one
getSubscription(reg)
.then(
getSubscription(reg).then(
function(subscription) {
postSubscribeObj('subscribe',subscription);
}
Expand All @@ -91,16 +90,40 @@ function subscribe(reg) {
)
}

function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');

const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);

for (var i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}

function getSubscription(reg) {
return reg.pushManager.getSubscription()
.then(
return reg.pushManager.getSubscription().then(
function(subscription) {
var metaObj, applicationServerKey, options;
// Check if Subscription is available
if (subscription) {
return subscription;
}

metaObj = document.querySelector('meta[name="django-webpush-vapid-key"]');
applicationServerKey = metaObj.content;
options = {
userVisibleOnly: true
};
if (applicationServerKey){
options.applicationServerKey = urlB64ToUint8Array(applicationServerKey)
}
// If not, register one
return registration.pushManager.subscribe({ userVisibleOnly: true });
return registration.pushManager.subscribe(options)
}
)
}
Expand Down
2 changes: 1 addition & 1 deletion webpush/static/webpush/webpush_serviceworker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ self.addEventListener('push', function(event) {
// Show a notification with title 'ServiceWorker Cookbook' and use the payload
// as the body.
self.registration.showNotification(head, {
body: body,
body: body
})
);
});
2 changes: 1 addition & 1 deletion webpush/templates/webpush.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

<script id="webpush-js" type="text/javascript" src="{% static 'webpush/webpush.js' %}"></script>
<script id="service-worker-js" type="text/javascript" src="{% static 'webpush/webpush_serviceworker.js' %}"></script>
<link rel="manifest" href="{% url 'webpush_manifest_json' %}">
<meta name="django-webpush-vapid-key" content="{{ vapid_public_key }}">
{% endif %}
4 changes: 3 additions & 1 deletion webpush/templatetags/webpush_notifications.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django import template
from django.conf import settings
from django.core.urlresolvers import reverse

register = template.Library()
Expand All @@ -8,8 +9,9 @@
@register.inclusion_tag('webpush.html', takes_context=True)
def webpush(context):
group = context.get('webpush', {}).get('group')
vapid_public_key = getattr(settings, 'WEBPUSH_SETTINGS', {}).get('VAPID_PUBLIC_KEY', '')
request = context['request']
return {'group': group, 'request': request}
return {'group': group, 'request': request, 'vapid_public_key': vapid_public_key}


@register.filter
Expand Down
1 change: 0 additions & 1 deletion webpush/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@

urlpatterns = [
url(r'^save_information', views.save_info, name='save_webpush_info'),
url(r'^manifest', views.generate_manifest, name='webpush_manifest_json'),
]
24 changes: 17 additions & 7 deletions webpush/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.conf import settings
from django.forms.models import model_to_dict

from pywebpush import WebPusher
from pywebpush import webpush


def send_notification_to_user(user, payload, ttl=0):
Expand All @@ -22,14 +22,24 @@ def send_notification_to_group(group_name, payload, ttl=0):
def _send_notification(push_info, payload, ttl):
subscription = push_info.subscription
subscription_data = _process_subscription_info(subscription)
# Check if GCM info is provided in the settings
if hasattr(settings,'WEBPUSH_SETTINGS'):
gcm_key = settings.WEBPUSH_SETTINGS.get('GCM_KEY')
else:
gcm_key = None
req = WebPusher(subscription_data).send(data=payload, ttl=ttl, gcm_key=gcm_key)
vapid_data = {}

webpush_settings = getattr(settings, 'WEBPUSH_SETTINGS', {})
vapid_private_key = webpush_settings.get('VAPID_PRIVATE_KEY')
vapid_admin_email = webpush_settings.get('VAPID_ADMIN_EMAIL')

# Vapid keys are optional, and mandatory only for Chrome.
# If Vapid key is provided, include vapid key and claims
if vapid_private_key:
vapid_data = {
'vapid_private_key': vapid_private_key,
'vapid_claims': {"sub": "mailto:{}".format(vapid_admin_email)}
}

req = webpush(subscription_info=subscription_data, data=payload, ttl=ttl, **vapid_data)
return req


def _process_subscription_info(subscription):
subscription_data = model_to_dict(subscription, exclude=["browser", "id"])
endpoint = subscription_data.pop("endpoint")
Expand Down
17 changes: 2 additions & 15 deletions webpush/views.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import json

from django.conf import settings
from django.core.exceptions import FieldError
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST, require_GET

from .config import MANIFEST
from .forms import WebPushForm, SubscriptionForm


Expand Down Expand Up @@ -37,7 +32,7 @@ def save_info(request):
if request.user.is_authenticated() or group_name:
# Save the subscription info with subscription data
# as the subscription data is a dictionary and its valid
subscription = subscription_form.get_or_save(subscription_data)
subscription = subscription_form.get_or_save()
web_push_form.save_or_delete(
subscription=subscription, user=request.user,
status_type=status_type, group_name=group_name)
Expand All @@ -52,14 +47,6 @@ def save_info(request):
return HttpResponse(status=400)


@require_GET
def generate_manifest(request):
if hasattr(settings,'WEBPUSH_SETTINGS'):
return JsonResponse(MANIFEST)
else:
return HttpResponse(status=404)


def process_subscription_data(post_data):
"""Process the subscription data according to out model"""
subscription_data = post_data.pop("subscription", {})
Expand Down

0 comments on commit aed8d52

Please sign in to comment.