214 lines
8.3 KiB
TypeScript
214 lines
8.3 KiB
TypeScript
|
||
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);
|
||
}
|
||
}
|
||
}
|