jazzband / django-push-notifications

Send push notifications to mobile devices through GCM or APNS in Django.
MIT License
2.26k stars 613 forks source link

How to setup properly just for web? #665

Closed saileshkush95 closed 11 months ago

saileshkush95 commented 2 years ago

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: development@example.com"}
}

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??.

gagamil commented 2 years ago

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:

viktorisacenko commented 2 years ago

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

gagamil commented 2 years ago

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.

blighj commented 1 year ago

@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

azmeuk commented 11 months ago

Fixed by #674