django-push-notifications icon indicating copy to clipboard operation
django-push-notifications copied to clipboard

How to setup properly just for web?

Open saileshkush95 opened this issue 2 years ago • 3 comments

I want to setup push notification for website. I just follwed as described in documenation but Unfurtunately it is now working.

Here is my settings.

PUSH_NOTIFICATIONS_SETTINGS = {
    "WP_PRIVATE_KEY": BASE_DIR / 'private_key.perm',
    "WP_CLAIMS": {'sub': "mailto: [email protected]"}
}

and here is my client side code

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Push Notifications</title>
</head>
<body>
<h1>Push Notification Example</h1>
<script>
  // Utils functions:
  function urlBase64ToUint8Array(base64String) {
    var padding = '='.repeat((4 - base64String.length % 4) % 4)
    var base64 = (base64String + padding)
      .replace(/\-/g, '+')
      .replace(/_/g, '/')

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

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

  function loadVersionBrowser(userAgent) {
    var ua = userAgent;
    var tem;
    var M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
    if (/trident/i.test(M[1])) {
      tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
      return {name: 'IE', version: (tem[1] || '')};
    }
    if (M[1] === 'Chrome') {
      tem = ua.match(/\bOPR\/(\d+)/);
      if (tem != null) {
        return {name: 'Opera', version: tem[1]};
      }
    }
    M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
    if ((tem = ua.match(/version\/(\d+)/i)) != null) {
      M.splice(1, 1, tem[1]);
    }
    return {
      name: M[0],
      version: M[1]
    };
  };
  var applicationServerKey = "BLygs7rQA7nPjI2JK4XEEcVB5gvpHZpOGJ5ldEXMYzRzj9DmcpxlLnfLrVzS-TlQ7cL9dO1C8WRFOtqpMrgk1tI";
  // In your ready listener
  if ('serviceWorker' in navigator) {
    // The service worker has to store in the root of the app
    // http://stackoverflow.com/questions/29874068/navigator-serviceworker-is-never-ready
    var browser = loadVersionBrowser('chrome');
    navigator.serviceWorker.register('navigatorPush.service.js?version=1.0.0').then(function (reg) {
      reg.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(applicationServerKey)
      }).then(function (sub) {
        var endpointParts = sub.endpoint.split('/');
        var registration_id = endpointParts[endpointParts.length - 1];
        var data = {
          'browser': browser.name.toUpperCase(),
          'p256dh': btoa(String.fromCharCode.apply(null, new Uint8Array(sub.getKey('p256dh')))),
          'auth': btoa(String.fromCharCode.apply(null, new Uint8Array(sub.getKey('auth')))),
          'name': 'XXXXX',
          'registration_id': registration_id
        };
        console.log(data);
      })
    }).catch(function (err) {
      console.log(':^(', err);
    });
  }
</script>
</body>
</html>

and here is error snippets. Screenshot from 2022-07-17 13-42-11

I don't know what I'm missing??.

saileshkush95 avatar Jul 17 '22 08:07 saileshkush95

I am setting up only the Web push too and somehow not sure how exactly to set up. Also not sure what API endpoint are there to start using the web push:

  • is there an API endpoint to create the subscription?
  • how exactly to set up the library (what keys are required and what claims are)?
  • should I expose the public key to the client app myself? The documentation is not clear on this. Guess will have to read the sources (this and the dependency library pywebpush) and deduce what is what. P.S. Googled but didn't find any complete example on how to setup this specific library.

gagamil avatar Sep 12 '22 11:09 gagamil

For the api endpoints to register the device you need to add the url's from the rest package.

from rest_framework.routers import SimpleRouter
from push_notifications.api.rest_framework import WebPushDeviceViewSet
....
api_router = SimpleRouter()
api_router.register(r'push/web', WebPushDeviceViewSet, basename='web_push')
...
urlpatterns += [
    # Api
    re_path('api/v1/', include(api_router.urls)),
    ...
]

On the client/Device you can now send the data for registration with a POST Method to your django.

Something like:

....
      }).then(function (sub) {
        var endpointParts = sub.endpoint.split('/');
        var registration_id = endpointParts[endpointParts.length - 1];
        var data = {
          'browser': browser.name.toUpperCase(),
          'p256dh': btoa(String.fromCharCode.apply(null, new Uint8Array(sub.getKey('p256dh')))),
          'auth': btoa(String.fromCharCode.apply(null, new Uint8Array(sub.getKey('auth')))),
          'name': 'XXXXX',
          'registration_id': registration_id
        };
        console.log(data);
        requestPOSTToServer(data);    <---------
      })
....

function requestPOSTToServer(data) {
    let xhr = new XMLHttpRequest();
    xhr.open("POST", "https://<YOUR_ADDRESS/push/web/");
    
    xhr.setRequestHeader("Accept", "application/json");
    xhr.setRequestHeader("Content-Type", "application/json");
    
    xhr.onload = () => console.log(xhr.responseText);

    xhr.send(data);
}

Then your devices are registered #658

viktorisacenko avatar Sep 15 '22 09:09 viktorisacenko

For the api endpoints to register the device you need to add the url's from the rest package.

from rest_framework.routers import SimpleRouter
from push_notifications.api.rest_framework import WebPushDeviceViewSet
....
api_router = SimpleRouter()
api_router.register(r'push/web', WebPushDeviceViewSet, basename='web_push')
...
urlpatterns += [
    # Api
    re_path('api/v1/', include(api_router.urls)),
    ...
]

On the client/Device you can now send the data for registration with a POST Method to your django.

Something like:

....
      }).then(function (sub) {
        var endpointParts = sub.endpoint.split('/');
        var registration_id = endpointParts[endpointParts.length - 1];
        var data = {
          'browser': browser.name.toUpperCase(),
          'p256dh': btoa(String.fromCharCode.apply(null, new Uint8Array(sub.getKey('p256dh')))),
          'auth': btoa(String.fromCharCode.apply(null, new Uint8Array(sub.getKey('auth')))),
          'name': 'XXXXX',
          'registration_id': registration_id
        };
        console.log(data);
        requestPOSTToServer(data);    <---------
      })
....

function requestPOSTToServer(data) {
    let xhr = new XMLHttpRequest();
    xhr.open("POST", "https://<YOUR_ADDRESS/push/web/");
    
    xhr.setRequestHeader("Accept", "application/json");
    xhr.setRequestHeader("Content-Type", "application/json");
    
    xhr.onload = () => console.log(xhr.responseText);

    xhr.send(data);
}

Then your devices are registered #658

Thank you. That's basically what I ended up doing. Just wondering why was this so hard for me to do? Will try to share the concepts using the library. Also noticed that there is no Safari browser in the browser list.

gagamil avatar Sep 15 '22 13:09 gagamil

@gagamil @viktorisacenko @saileshkush95 Any feedback on this PR, #674, specfically this file, which aims to explain wepush configuration https://github.com/jazzband/django-push-notifications/blob/4fb64be08a5e9d4b9275e9632426d022d5a84a70/docs/WebPush.rst

blighj avatar Nov 21 '22 07:11 blighj

Fixed by #674

azmeuk avatar Oct 29 '23 17:10 azmeuk