diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | backend/main.py | 12 | ||||
| -rw-r--r-- | backend/notif.py | 59 | ||||
| -rw-r--r-- | frontend/main.js | 46 | ||||
| -rw-r--r-- | frontend/permissionrequest.js | 16 |
5 files changed, 120 insertions, 15 deletions
@@ -1,3 +1,5 @@ db.db .env config.yaml +private_key.pem +public_key.pem diff --git a/backend/main.py b/backend/main.py index d77fdd1..fec436b 100644 --- a/backend/main.py +++ b/backend/main.py @@ -17,6 +17,7 @@ from enum import Enum, IntEnum from dotenv import load_dotenv from os import getenv import yaml +import notif # import notif.py # ## API, db, and scheduler initialisation app = fastapi.FastAPI(title="Victoria Hall LaundryWeb", description="LaundryWeb Backend API", version="0.1") @@ -443,3 +444,14 @@ def uri_to_information(data: InformationRequestData, response: fastapi.Response, return "NO INFORMATION PROVIDED. NO AUTH COOKIE." return {"block": info[0], "machine": info[1]} + + +# #### NOTIFICATION API END POINTS #### + + +# --- subscribe +@app.post("/notif_subscribe") +def notif_subscribe(data: notif.PushSubscriptionData, response: fastapi.Response): + endpoint = notif.subscribe(data) + response.set_cookie("subscription_endpoint", endpoint) + response.status_code = fastapi.status.HTTP_200_OK diff --git a/backend/notif.py b/backend/notif.py new file mode 100644 index 0000000..59bb3c3 --- /dev/null +++ b/backend/notif.py @@ -0,0 +1,59 @@ +from pydantic import BaseModel +import sqlite3 +from pywebpush import webpush + + +class PushSubscriptionData(BaseModel): + endpoint: str + expirationTime: float + keys: object + + +conn = sqlite3.connect("db.db", check_same_thread=False) +cursor = conn.cursor() + +f = open("private_key.pem", "r") +PRIVATE_VAPID_KEY = f.read() +f.close() + +cursor.execute(""" +CREATE TABLE IF NOT EXISTS subscriptions ( + endpoint TEXT PRIMARY KEY, + expiration_time REAL NOT NULL, + keys_p256dh TEXT NOT NULL, + keys_auth TEXT NOT NULL +);""") + + +# --- subscribe +def subscribe(data: PushSubscriptionData): + cursor.execute(""" + INSERT INTO subscriptions (endpoint, expiration_time, keys_p256dh, keys_auth) + VALUES (?, ?, ?, ?)""", (data.endpoint, data.expirationTime, data.keys["p256dh"], data.keys["auth"])) + conn.commit() + return data.endpoint + + +# --- send notification +def send_notification(endpoint: str): + cursor.execute("SELECT * FROM subscriptions WHERE endpoint = ?", (endpoint,)) + row = cursor.fetchall()[0] + subscription_info = { + "endpoint": endpoint, + "keys": { + "p256dh": row[2], + "auth": row[3], + }, + } + + try: + webpush( + subscription_info=subscription_info, + data="Hello, world!", + vapid_private_key=PRIVATE_VAPID_KEY, + vapid_claims={ + "sub": "mailto:dev@altafcreator.com", + }, + ) + except Exception as exception: + print(exception) diff --git a/frontend/main.js b/frontend/main.js index 1434979..b8803c0 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -7,6 +7,52 @@ const data = { const API_URL = "https://backend.laundryweb.altafcreator.com" +const PUBLIC_VAPID_KEY = "BCvVfKfWBtHKtzdakJfhYy604yTn0_FgZxy2sNtxcQm6YyC3qdzBBuCJLbVcG6pmbz_CZLa0I44Z-b5UVBbegGw" + +// --- REGISTER SERVICE WORKERS +if ('serviceWorker' in navigator) { + navigator.serviceWorker.register('/sw.js', { + scope: '/', + }); +} + +// --- subscribe +async function subscribe() { + if (!('serviceWorker' in navigator)) return; + + const registration = await navigator.serviceWorker.ready; + + const subscription = await registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: urlBase64ToUint8Array(PUBLIC_VAPID_KEY), + }); + console.log(subscription); + + await fetch(`${API_URL}/notif_subscribe`, { + method: 'POST', + body: JSON.stringify(subscription), + headers: { + "Content-Type": "application/json", + }, + }) +} + +/// copied from somewhere +const urlBase64ToUint8Array = (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; +}; + // --- check machine status // returns a 2d array representing machines // []: root array diff --git a/frontend/permissionrequest.js b/frontend/permissionrequest.js index 2303347..0c8d4d9 100644 --- a/frontend/permissionrequest.js +++ b/frontend/permissionrequest.js @@ -19,19 +19,5 @@ console.log("notbtn") notbtn.addEventListener("click", () => requestPermission()) async function requestPermission() { - try { - - console.log("Requesting permission..."); - const onesignal_result = await OneSignal.Notifications.requestPermission(); - alert("succ", onesignal_result.toString(), OneSignal.toString()); - console.log(onesignal_result); - if (onesignal_result) { - notif.remove(); - startbtn.disabled = false; - data.onesignal_subscription_id = OneSignal.User.PushSubscription["id"]; - } - } - catch (e) { - alert("err:", e, e.toString()); - } + subscribe() } |
