Partial addition of push notifications.

Push notifications are the next step and this is an intermediary step to that goal.
pull/6/head
Hailey Clark 4 years ago
parent 954f4355ca
commit 018a7b9a04
  1. 6
      .gitignore
  2. 58
      smsproj.py
  3. 171
      static/main.js
  4. 64
      static/sw.js
  5. 1
      templates/inbox.html
  6. 2
      templates/include/header.html

6
.gitignore vendored

@ -32,3 +32,9 @@ static/img/davecat.jpg
static/yoyo-medium.gif
static/leo.goldfish.fyi.png
private_key.txt
public_key.txt
vapid_private.pem

@ -6,9 +6,12 @@ import time
import pprint
import configparser
import json
# import re
import os
import flask
# import re
from flask import request, Response, render_template, jsonify, Flask, session
from pywebpush import webpush, WebPushException
import appdb
import appsms
@ -20,8 +23,18 @@ config = configparser.ConfigParser()
config.read('config.ini')
app_debug = config.get("app", "debug")
app = flask.Flask(__name__)
app = Flask(__name__)
app.secret_key = config.get("auth", "FN_FLASK_SECRET_KEY")
app.config['SECRET_KEY'] = config.get("auth", "FN_FLASK_SECRET_KEY")
DER_BASE64_ENCODED_PRIVATE_KEY_FILE_PATH = os.path.join(os.getcwd(),"private_key.txt")
DER_BASE64_ENCODED_PUBLIC_KEY_FILE_PATH = os.path.join(os.getcwd(),"public_key.txt")
VAPID_PRIVATE_KEY = open(DER_BASE64_ENCODED_PRIVATE_KEY_FILE_PATH, "r+").readline().strip("\n")
VAPID_PUBLIC_KEY = open(DER_BASE64_ENCODED_PUBLIC_KEY_FILE_PATH, "r+").read().strip("\n")
VAPID_CLAIMS = {
"sub": "mailto:support@athnex.com"
}
app.register_blueprint(callback_sms.app)
app.register_blueprint(app_settings.app)
@ -34,6 +47,13 @@ if app_debug == '1':
else:
app.debug = False
def send_web_push(subscription_information, message_body):
return webpush(
subscription_info=subscription_information,
data=message_body,
vapid_private_key=VAPID_PRIVATE_KEY,
vapid_claims=VAPID_CLAIMS
)
@app.route('/')
def index():
@ -105,7 +125,7 @@ def getNumMessages(number):
'''Return the messages from a single DID in json form'''
# This gets the mssages based on the provided from or two DID
if not app_auth.is_logged_in():
return json.dumps({'error': 'Unable to send SMS, you are not logged in'})
return json.dumps({'error': 'You are not logged in.'})
# We need to take and compare the authIDforDID, gotta add use id
# to getNumSMSLog and pull the id from result.
@ -174,6 +194,20 @@ def markallunread():
return json.dumps({'status': 'success'})
return False
@app.route("/subscription/", methods=["GET", "POST"])
def subscription():
"""
POST creates a subscription
GET returns vapid public key which clients uses to send around push notification
"""
if request.method == "GET":
return Response(response=json.dumps({"public_key": VAPID_PUBLIC_KEY}),
headers={"Access-Control-Allow-Origin": "*"}, content_type="application/json")
subscription_token = request.get_json("subscription_token")
return Response(status=201, mimetype="application/json")
@app.route('/submitMessage', methods=['POST'])
def submitMessage():
@ -215,6 +249,24 @@ def submitMessage():
"targetdid": targetDid})
return returndata
@app.route("/push_v1/",methods=['POST'])
def push_v1():
message = "Push Test v1"
print("is_json",request.is_json)
if not request.json or not request.json.get('sub_token'):
return jsonify({'failed':1})
print("request.json",request.json)
token = request.json.get('sub_token')
try:
token = json.loads(token)
send_web_push(token, message)
return jsonify({'success':1})
except Exception as e:
print("error",e)
return jsonify({'failed':str(e)})
@app.route('/testAjax')
def testAjax():

@ -0,0 +1,171 @@
// main.js
'use strict';
// const applicationServerPublicKey = "BNbxGYNMhEIi9zrneh7mqV4oUanjLUK3m+mYZBc62frMKrEoMk88r3Lk596T0ck9xlT+aok0fO1KXBLV4+XqxYM=";
const pushButton = document.querySelector('.js-push-btn');
let isSubscribed = false;
let swRegistration = null;
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 (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function updateBtn() {
if (Notification.permission === 'denied') {
pushButton.textContent = 'Push Messaging Blocked.';
pushButton.disabled = true;
updateSubscriptionOnServer(null);
return;
}
if (isSubscribed) {
pushButton.textContent = 'Disable Push Messaging';
} else {
pushButton.textContent = 'Enable Push Messaging';
}
pushButton.disabled = false;
}
function updateSubscriptionOnServer(subscription) {
// TODO: Send subscription to application server
const subscriptionJson = document.querySelector('.js-subscription-json');
const subscriptionDetails =
document.querySelector('.js-subscription-details');
if (subscription) {
subscriptionJson.textContent = JSON.stringify(subscription);
subscriptionDetails.classList.remove('is-invisible');
} else {
subscriptionDetails.classList.add('is-invisible');
}
}
function subscribeUser() {
const applicationServerPublicKey = localStorage.getItem('applicationServerPublicKey');
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
.then(function(subscription) {
console.log('User is subscribed.');
updateSubscriptionOnServer(subscription);
localStorage.setItem('sub_token',JSON.stringify(subscription));
isSubscribed = true;
updateBtn();
})
.catch(function(err) {
console.log('Failed to subscribe the user: ', err);
updateBtn();
});
}
function unsubscribeUser() {
swRegistration.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription.unsubscribe();
}
})
.catch(function(error) {
console.log('Error unsubscribing', error);
})
.then(function() {
updateSubscriptionOnServer(null);
console.log('User is unsubscribed.');
isSubscribed = false;
updateBtn();
});
}
function initializeUI() {
pushButton.addEventListener('click', function() {
pushButton.disabled = true;
if (isSubscribed) {
unsubscribeUser();
} else {
subscribeUser();
}
});
// Set the initial subscription value
swRegistration.pushManager.getSubscription()
.then(function(subscription) {
isSubscribed = !(subscription === null);
updateSubscriptionOnServer(subscription);
if (isSubscribed) {
console.log('User IS subscribed.');
} else {
console.log('User is NOT subscribed.');
}
updateBtn();
});
}
if ('serviceWorker' in navigator && 'PushManager' in window) {
console.log('Service Worker and Push is supported');
navigator.serviceWorker.register("/static/sw.js")
.then(function(swReg) {
console.log('Service Worker is registered', swReg);
swRegistration = swReg;
initializeUI();
})
.catch(function(error) {
console.error('Service Worker Error', error);
});
} else {
console.warn('Push meapplicationServerPublicKeyssaging is not supported');
pushButton.textContent = 'Push Not Supported';
}
function push_message() {
console.log("sub_token", localStorage.getItem('sub_token'));
$.ajax({
type: "POST",
url: "/push_v1/",
contentType: 'application/json; charset=utf-8',
dataType:'json',
data: JSON.stringify({'sub_token':localStorage.getItem('sub_token')}),
success: function( data ){
console.log("success",data);
},
error: function( jqXhr, textStatus, errorThrown ){
console.log("error",errorThrown);
}
});
}
$(document).ready(function(){
$.ajax({
type:"GET",
url:'/subscription/',
success:function(response){
console.log("response",response);
localStorage.setItem('applicationServerPublicKey',response.public_key);
}
})
});

@ -0,0 +1,64 @@
// sw.js
'use strict';
/* eslint-disable max-len */
// const applicationServerPublicKey = "BNbxGYNMhEIi9zrneh7mqV4oUanjLUK3m+mYZBc62frMKrEoMk88r3Lk596T0ck9xlT+aok0fO1KXBLV4+XqxYM=";
/* eslint-enable max-len */
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 (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
self.addEventListener('push', function(event) {
console.log('[Service Worker] Push Received.');
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
const title = 'Push Codelab';
const options = {
body: `"${event.data.text()}"`,
icon: 'images/icon.png',
badge: 'images/badge.png'
};
event.waitUntil(self.registration.showNotification(title, options));
});
self.addEventListener('notificationclick', function(event) {
console.log('[Service Worker] Notification click Received.');
event.notification.close();
event.waitUntil(
clients.openWindow('https://developers.google.com/web/')
);
});
self.addEventListener('pushsubscriptionchange', function(event) {
console.log('[Service Worker]: \'pushsubscriptionchange\' event fired.');
const applicationServerPublicKey = localStorage.getItem('applicationServerPublicKey');
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
event.waitUntil(
self.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
.then(function(newSubscription) {
// TODO: Send to application server
console.log('[Service Worker] New subscription: ', newSubscription);
})
);
});

@ -52,6 +52,7 @@ $("document").ready(function() {
alert("FAIL");
});
}
getInboxData();
});
</script>
</head>

@ -4,6 +4,8 @@
<link rel="stylesheet" href="/static/main.css">
<script src="/static/jquery-3.5.1.min.js"></script>
<script src='/static/functions.js'></script>
<script src='{{ url_for('static',filename='sw.js') }}'></script>
<script src="{{ url_for('static',filename='main.js') }}"></script>
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">

Loading…
Cancel
Save