const webPush = require('web-push') import common from '../../src/helpers/common'; //generate and store VAPID keys in .env.local if not already done if (!process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY || !process.env.WEB_PUSH_PRIVATE_KEY) { const { publicKey, privateKey } = webPush.generateVAPIDKeys() console.log('VAPID keys generated:') console.log('Public key:', publicKey) console.log('Private key:', privateKey) console.log('Store these keys in your .env.local file:') console.log('NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY=', publicKey) console.log('WEB_PUSH_PRIVATE_KEY=', privateKey) process.exit(0) } webPush.setVapidDetails( `mailto:${process.env.WEB_PUSH_EMAIL}`, process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY, process.env.WEB_PUSH_PRIVATE_KEY ) const Notification = async (req, res) => { if (req.method == 'GET') { res.statusCode = 200 res.setHeader('Allow', 'POST') let subs = 0 if (req.query && req.query.id) { const prisma = common.getPrismaClient(); const publisher = await prisma.publisher.findUnique({ where: { id: req.query.id }, select: { pushSubscription: true } }); subs = Array.isArray(publisher.pushSubscription) ? publisher.pushSubscription.length : (publisher.pushSubscription ? 1 : 0); res.send({ subs }) res.end() return } else { // send the public key in the response headers //res.setHeader('Content-Type', 'text/plain') res.send({ pk: process.env.NEXT_PUBLIC_WEB_PUSH_PUBLIC_KEY, subs }) res.end() } } if (req.method == 'PUT') { // store the subscription object in the database // publisher.pushSubscription = subscription const prisma = common.getPrismaClient(); const { subscription, id, name } = req.body const publisher = await prisma.publisher.findUnique({ where: { id }, select: { pushSubscription: true } }); if (!publisher) { res.statusCode = 404 res.end() return } let subscriptions = Array.isArray(publisher.pushSubscription) ? publisher.pushSubscription : (publisher.pushSubscription ? [publisher.pushSubscription] : []); const index = subscriptions.findIndex(sub => sub.endpoint === subscription.endpoint); if (index !== -1) { subscriptions[index] = subscription; // Update existing subscription console.log('Subscription for publisher', id, 'updated.') } else { subscriptions.push(subscription); // Add new subscription console.log('Subscription for publisher', id, 'saved.') } await prisma.publisher.update({ where: { id }, data: { pushSubscription: subscriptions } }); console.log('Subscription update successful', subscription.keys.auth, ". Total subscriptions:", subscriptions.length) res.send({ subs: subscriptions.length }) res.statusCode = 200 res.end() } if (req.method == 'DELETE') { // remove the subscription object from the database // publisher.pushSubscription = null const prisma = common.getPrismaClient(); const { subscriptionId, id } = req.body; const publisher = await prisma.publisher.findUnique({ where: { id }, select: { pushSubscription: true } }); let subscriptions = Array.isArray(publisher.pushSubscription) ? publisher.pushSubscription : (publisher.pushSubscription ? [publisher.pushSubscription] : []); try { subscriptions = subscriptionId ? subscriptions.filter(sub => sub.endpoint !== subscriptionId) : []; await prisma.publisher.update({ where: { id }, data: { pushSubscription: subscriptions } }); } catch (e) { console.log(e) await prisma.publisher.update({ where: { id }, data: { pushSubscription: null } }); } console.log('Subscription for publisher', id, 'deleted') res.send({ subs: subscriptions.length }) res.statusCode = 200 res.end() } if (req.method == 'POST') {//title = "ССС", message = "Ще получите уведомление по този начин.") const { subscription, id, ids, broadcast, title = 'ССОМ', message = 'Ще получавате уведомления така.', actions } = req.body if (broadcast) { await broadcastPush(title, message, actions) res.statusCode = 200 res.end() return } else if (ids && ids.length) { console.log('Sending push notifications to publishers ', ids); await Promise.all(ids.map(_id => sendPush(_id, title, message, actions))); res.statusCode = 200; res.end(); return; } else if (id) { console.log('Sending push notification to publisher ', id) await sendPush(id, title, message, actions) res.statusCode = 200 res.end() return } else if (subscription) { await webPush .sendNotification( subscription, JSON.stringify({ title, message, actions }) ) .then(response => { res.writeHead(response.statusCode, response.headers).end(response.body) }) .catch(err => { if ('statusCode' in err) { res.writeHead(err.statusCode, err.headers).end(err.body) } else { console.error(err) res.statusCode = 500 res.end() } }) } } else { res.statusCode = 405 res.end() } } export default Notification //export pushNotification(userId or email) for use in other files export const sendPush = async (id, title, message, actions) => { const prisma = common.getPrismaClient(); const publisher = await prisma.publisher.findUnique({ where: { id } }) if (publisher.pushSubscription && Array.isArray(publisher.pushSubscription) && publisher.pushSubscription.length) { for (const subscription of publisher.pushSubscription) { await webPush .sendNotification( subscription, JSON.stringify({ title, message, actions }) ) .then(response => { console.log('Push notification sent to publisher', id) }) .catch(err => { console.error('Error sending push notification to publisher', id, ':', err) }) } } else { console.log('No valid subscriptions found for publisher', id) } } //export breoadcastNotification for use in other files export const broadcastPush = async (title, message, actions) => { const prisma = common.getPrismaClient(); const publishers = await prisma.publisher.findMany({ where: { pushSubscription: { not: null } } }) for (const publisher of publishers) { if (Array.isArray(publisher.pushSubscription) && publisher.pushSubscription.length) { for (const subscription of publisher.pushSubscription) { await webPush.sendNotification( subscription, // Here subscription is each individual subscription object JSON.stringify({ title, message, actions }) ) .then(response => { console.log('Push notification sent to device', subscription.endpoint, 'of publisher', publisher.id); }) .catch(err => { console.error('Error sending push notification to device', subscription.endpoint, 'of publisher', publisher.id, ':', err); // Optionally handle failed subscriptions, e.g., remove outdated or invalid subscriptions }); } } else { console.log('No valid subscriptions found for publisher', publisher.id); } } }