Skip to content

Commit

Permalink
v3
Browse files Browse the repository at this point in the history
  • Loading branch information
konavivekramakrishna committed Aug 20, 2024
1 parent af5d8d3 commit fc967ef
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 107 deletions.
111 changes: 70 additions & 41 deletions frontend/public/service-worker.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,84 @@
// Any other custom service worker logic can go here.
// Define a cache name for versioning your cache
const CACHE_NAME = 'my-cache-v1';

self.addEventListener("push", async function (event) {
// Cache assets during the install phase
self.addEventListener('install', (event) => {
console.log('[Service Worker] Install');
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([
'/',
'/index.html',
'/styles.css',
]);
}).then(() => self.skipWaiting()) // Skip waiting to activate new service worker immediately
);
});

// Clean up old caches during the activate phase
self.addEventListener('activate', (event) => {
console.log('[Service Worker] Activate');
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
console.log('[Service Worker] Deleting old cache:', cacheName);
return caches.delete(cacheName);
}
})
);
}).then(() => self.clients.claim()) // Take control of all clients as soon as active
);
});



// Listen for push events and display notifications
self.addEventListener('push', (event) => {
console.log('[Service Worker] Push Received', event);
if (event.data) {
const data = event.data.json();
const notificationOptions = {
body: data.body || "Sample Body",
tag: data.external_id || "default-tag",
body:data.body || 'Message Received from OpenELIS',
tag: data.external_id || 'default-tag',
icon: 'images/openelis_logo.png',
};

event.waitUntil(
self.registration.showNotification(
"OpenELIS Test Message Received",
notificationOptions,
),
self.registration.showNotification('OpenELIS Test Message Received', notificationOptions)
);
}
});

// This allows the web app to trigger skipWaiting via
// registration.waiting.postMessage({type: 'SKIP_WAITING'})
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") {
// Notification click event listener
// self.addEventListener("notificationclick", (event) => {
// console.log('Notification clicked');
// event.notification.close(); // Close the notification popout

// event.waitUntil(
// clients.matchAll({ type: 'window', includeUncontrolled: true }).then((clientList) => {
// // Check if any client (tab or window) is already open
// for (let i = 0; i < clientList.length; i++) {
// const client = clientList[i];
// if (client.url === 'https://www.youtube.com/' && 'focus' in client) {
// return client.focus();
// }
// }

// // If no client is open, open a new window
// if (clients.openWindow) {
// return clients.openWindow('https://www.youtube.com/');
// }
// })
// );
// });



// Handle messages from clients
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});

// self.addEventListener('push', (e) => {
// const data = e.data?.json();
// if (data) {
// self.registration.showNotification(data.title, {
// body: data.body,
// });
// }
// });

// self.addEventListener('notificationclick', (e) => {
// e.notification.close();
// e.waitUntil(focusOrOpenWindow());
// });

// async function focusOrOpenWindow() {
// const url = new URL('/', self.location.origin).href;

// const allWindows = await self.clients.matchAll({
// type: 'window',
// });
// const appWindow = allWindows.find((w) => w.url === url);

// if (appWindow) {
// return appWindow.focus();
// } else {
// return self.clients.openWindow(url);
// }
// }
78 changes: 59 additions & 19 deletions frontend/src/components/notifications/SlideOverNotifications.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,89 @@ export default function SlideOverNotifications(props) {

async function subscribe() {
try {
// Set the loading state
setIconLoading({ icon: "NOTIFICATION", loading: true });

// Attempt to retrieve the public key from the server
let pbKeyData = await getFromOpenElisServerV2("/rest/notification/public_key");
// Check if service workers are supported
if (!('serviceWorker' in navigator)) {
throw new Error("Service workers are not supported in this browser.");
}

// Check if push messaging is supported
if (!('PushManager' in window)) {
throw new Error("Push messaging is not supported in this browser.");
}

// Register the service worker if not already registered
const registration = await navigator.serviceWorker.register('/service-worker.js').catch(error => {
throw new Error("Service worker registration failed: " + error.message);
});

// Attempt to get the service worker registration
// Ensure the service worker is ready
const sw = await navigator.serviceWorker.ready;

// Attempt to retrieve the public key from the server
let pbKeyData = await getFromOpenElisServerV2("/rest/notification/public_key").catch(error => {
throw new Error("Failed to retrieve public key from server: " + error.message);
});

// Convert the public key to a Uint8Array
const applicationServerKey = urlBase64ToUint8Array(pbKeyData.publicKey);

// Attempt to subscribe to push notifications
const push = await sw.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: pbKeyData.publicKey,
applicationServerKey,
}).catch(error => {
throw new Error("Push subscription failed: " + error.message);
});

// Encode the subscription keys
const p256dh = btoa(
String.fromCharCode.apply(null, new Uint8Array(push.getKey("p256dh"))),
);
const auth = btoa(
String.fromCharCode.apply(null, new Uint8Array(push.getKey("auth"))),
);
const p256dh = btoa(String.fromCharCode.apply(null, new Uint8Array(push.getKey("p256dh"))));
const auth = btoa(String.fromCharCode.apply(null, new Uint8Array(push.getKey("auth"))));

// Construct the data object
const data = {
pfEndpoint: push.endpoint,
pfP256dh: p256dh,
pfAuth : auth,
pfAuth: auth,
};

console.log("data",data)

postToOpenElisServer("/rest/notification/subscribe", JSON.stringify(data),(res)=>{
console.log("res",res);

console.log("data", data);

// Send the subscription data to the server
postToOpenElisServer("/rest/notification/subscribe", JSON.stringify(data), (res) => {
console.log("res", res);
});


// Set the loading state to false
setIconLoading({ icon: null, loading: false });
} catch (error) {
// Handle any errors that occurred during the process
console.error("An error occurred during the subscription process:", error);
setIconLoading({ icon: null, loading: false });
// You can also set an error state here if needed
// Optionally set an error state here or provide user feedback
}
}



// Helper function to convert a URL-safe base64 string to a Uint8Array
function 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;
}



const {
Expand Down Expand Up @@ -112,7 +152,7 @@ export default function SlideOverNotifications(props) {
<div style={{ display: "flex", flexDirection: "column", gap: "0.5rem" }}>

<br />

<div
style={{
display: "flex",
Expand Down
13 changes: 12 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@
<artifactId>hibernate-search-backend-lucene</artifactId>
<version>${hibernate-search.version}</version>
</dependency>
<!-- WEB PUSH DEPENDENCIES -->
<dependency>
<groupId>nl.martijndwars</groupId>
<artifactId>web-push</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.78</version>
</dependency>
<!-- JAVAX DEPENDENCIES -->
<dependency>
<groupId>javax.annotation</groupId>
Expand Down Expand Up @@ -681,4 +692,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public interface NotificationSubscriptionDAO {

void save(NotificationSubscriptions notificationSubscription);

NotificationSubscriptions getNotificationSubscriptionById(Long id);
NotificationSubscriptions getNotificationSubscriptionByUserId(Long id);

void updateNotificationSubscription(NotificationSubscriptions notificationSubscription);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.openelisglobal.notifications.dao;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import org.openelisglobal.notifications.entity.NotificationSubscriptions;
import org.springframework.stereotype.Repository;
Expand All @@ -20,12 +19,15 @@ public void save(NotificationSubscriptions notificationSubscription) {
}

@Override
public NotificationSubscriptions getNotificationSubscriptionById(Long id) {
public NotificationSubscriptions getNotificationSubscriptionByUserId(Long id) {

try {
return entityManager.find(NotificationSubscriptions.class, id);
} catch (NoResultException e) {
return entityManager.createQuery("SELECT ns FROM NotificationSubscriptions ns WHERE ns.user.id = :id",
NotificationSubscriptions.class).setParameter("id", id).getSingleResult();
} catch (Exception e) {
return null;
}

}

@Override
Expand All @@ -35,22 +37,22 @@ public void updateNotificationSubscription(NotificationSubscriptions notificatio
}

// Update saveOrUpdate method
@Transactional
public void saveOrUpdate(NotificationSubscriptions notificationSubscription) {


NotificationSubscriptions existingSubscription = getNotificationSubscriptionById(Long.valueOf(notificationSubscription.getUser().getId()));

if (existingSubscription == null) {
// Create a new subscription
entityManager.persist(notificationSubscription); // Use persist() for new entities
} else {
// Update the existing subscription
existingSubscription.setPfEndpoint(notificationSubscription.getPfEndpoint());
existingSubscription.setPfP256dh(notificationSubscription.getPfP256dh());
existingSubscription.setPfAuth(notificationSubscription.getPfAuth());
entityManager.merge(existingSubscription); // Use merge() for existing entities
@Transactional
public void saveOrUpdate(NotificationSubscriptions notificationSubscription) {

NotificationSubscriptions existingSubscription = getNotificationSubscriptionByUserId(
Long.valueOf(notificationSubscription.getUser().getId()));

if (existingSubscription == null) {
// Create a new subscription
entityManager.persist(notificationSubscription); // Use persist() for new entities
} else {
// Update the existing subscription
existingSubscription.setPfEndpoint(notificationSubscription.getPfEndpoint());
existingSubscription.setPfP256dh(notificationSubscription.getPfP256dh());
existingSubscription.setPfAuth(notificationSubscription.getPfAuth());
entityManager.merge(existingSubscription); // Use merge() for existing entities
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ public class NotificationSubscriptions {
@JoinColumn(name = "user_id", nullable = false)
private SystemUser user;

// Transient fields
@Transient
private String title;

@Transient
private String message;

public Long getId() {
return id;
}
Expand Down Expand Up @@ -65,12 +72,32 @@ public void setPfAuth(String pfAuth) {
this.pfAuth = pfAuth;
}


public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

@Override
public String toString() {
return "NotificationSubscription{" + "userId=" + ", pfEndpoint='" + pfEndpoint + '\'' + ", pfP256dh='"
+ pfP256dh + '\'' + ", pfAuth='" + pfAuth + '\'' + ", user=" + (user != null ? user.toString() : "null")
+ '}';
return "NotificationSubscription{" +
"userId=" + (user != null ? user.getId() : "null") +
", pfEndpoint='" + pfEndpoint + '\'' +
", pfP256dh='" + pfP256dh + '\'' +
", pfAuth='" + pfAuth + '\'' +
", user=" + (user != null ? user.toString() : "null") +
", title='" + title + '\'' +
", message='" + message + '\'' +
'}';
}
}
Loading

0 comments on commit fc967ef

Please sign in to comment.