Notifications

This commit is contained in:
aeroreyna
2022-03-13 23:01:49 -07:00
parent a3fc84fbad
commit ec2d16f3db
3 changed files with 134 additions and 21 deletions

View File

@@ -1,5 +1,84 @@
const nodemailer = require("nodemailer"); const nodemailer = require("nodemailer");
const DBGetter = require("./mongoDB.js"); const DBGetter = require("./mongoDB.js");
const { Expo } = require('expo-server-sdk');
const sendPushNotification = async (profileToken, body, data) => {
if(!profileToken) return 0;
let expo = new Expo();
// Create the messages that you want to send to clients
let messages = [];
let pushToken = profileToken;
if (!Expo.isExpoPushToken(pushToken)) {
console.error(`Push token ${pushToken} is not a valid Expo push token`);
return 0;
}
// Construct a message (see https://docs.expo.io/push-notifications/sending-notifications/)
messages.push({
to: pushToken,
sound: 'default',
body: body,
data: data,
})
let chunks = expo.chunkPushNotifications(messages);
let tickets = [];
(async () => {
for (let chunk of chunks) {
try {
let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
console.log(ticketChunk);
tickets.push(...ticketChunk);
// NOTE: If a ticket contains an error code in ticket.details.error, you
// must handle it appropriately. The error codes are listed in the Expo
// documentation:
// https://docs.expo.io/push-notifications/sending-notifications/#individual-errors
} catch (error) {
console.error(error);
}
}
})();
let receiptIds = [];
for (let ticket of tickets) {
// NOTE: Not all tickets have IDs; for example, tickets for notifications
// that could not be enqueued will have error information and no receipt ID.
if (ticket.id) {
receiptIds.push(ticket.id);
}
}
let receiptIdChunks = expo.chunkPushNotificationReceiptIds(receiptIds);
(async () => {
for (let chunk of receiptIdChunks) {
try {
let receipts = await expo.getPushNotificationReceiptsAsync(chunk);
console.log(receipts);
// The receipts specify whether Apple or Google successfully received the
// notification and information about an error, if one occurred.
for (let receiptId in receipts) {
let { status, message, details } = receipts[receiptId];
if (status === 'ok') {
continue;
} else if (status === 'error') {
console.error(
`There was an error sending a notification: ${message}`
);
if (details && details.error) {
// The error codes are listed in the Expo documentation:
// https://docs.expo.io/push-notifications/sending-notifications/#individual-errors
// You must handle the errors appropriately.
console.error(`The error code is ${details.error}`);
}
}
}
} catch (error) {
console.error(error);
}
}
})();
}
const sendEmail = async (to, subject, html) => { const sendEmail = async (to, subject, html) => {
let transporter = nodemailer.createTransport({ let transporter = nodemailer.createTransport({
@@ -18,7 +97,7 @@ const sendEmail = async (to, subject, html) => {
subject, subject,
html, html,
}).catch(console.error); }).catch(console.error);
if(info && info.messageId) console.log("Email sent: %s", info.messageId); if (info && info.messageId) console.log("Email sent: %s", info.messageId);
}; };
const yourBookmarkedPostGotACommentTemplate = (post, userEmail, postProfile, senderProfile, bookedProfile, message) => { const yourBookmarkedPostGotACommentTemplate = (post, userEmail, postProfile, senderProfile, bookedProfile, message) => {
@@ -151,32 +230,32 @@ const yourGroupHasARequestTemplate = (groupProfile, ownerEmail, senderProfile) =
sendEmail(ownerEmail, subject, html) sendEmail(ownerEmail, subject, html)
} }
const convertLinks = ( input ) => { const convertLinks = (input) => {
let text = input; let text = input;
const linksFound = text.match( /(?:www|https?)[^\s]+/g ); const linksFound = text.match(/(?:www|https?)[^\s]+/g);
const aLink = []; const aLink = [];
if ( linksFound != null ) { if (linksFound != null) {
for ( let i=0; i<linksFound.length; i++ ) { for (let i = 0; i < linksFound.length; i++) {
let replace = linksFound[i]; let replace = linksFound[i];
if ( !( linksFound[i].match( /(http(s?)):\/\// ) ) ) { replace = 'http://' + linksFound[i] } if (!(linksFound[i].match(/(http(s?)):\/\//))) { replace = 'http://' + linksFound[i] }
let linkText = replace.split( '/' )[2]; let linkText = replace.split('/')[2];
if ( linkText.substring( 0, 3 ) == 'www' ) { linkText = linkText.replace( 'www.', '' ) } if (linkText.substring(0, 3) == 'www') { linkText = linkText.replace('www.', '') }
if ( linkText.match( /youtu/ ) ) { if (linkText.match(/youtu/)) {
let youtubeID = replace.split( '/' ).slice(-1)[0]; let youtubeID = replace.split('/').slice(-1)[0];
aLink.push( '<div class="video-wrapper"><iframe src="https://www.youtube.com/embed/' + youtubeID + '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>' ) aLink.push('<div class="video-wrapper"><iframe src="https://www.youtube.com/embed/' + youtubeID + '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>')
} }
else if ( linkText.match( /vimeo/ ) ) { else if (linkText.match(/vimeo/)) {
let vimeoID = replace.split( '/' ).slice(-1)[0]; let vimeoID = replace.split('/').slice(-1)[0];
aLink.push( '<div class="video-wrapper"><iframe src="https://player.vimeo.com/video/' + vimeoID + '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>' ) aLink.push('<div class="video-wrapper"><iframe src="https://player.vimeo.com/video/' + vimeoID + '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>')
} }
else { else {
aLink.push( '<a href="' + replace + '" target="_blank">' + linkText + '</a>' ); aLink.push('<a href="' + replace + '" target="_blank">' + linkText + '</a>');
} }
text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] ); text = text.split(linksFound[i]).map(item => { return aLink[i].includes('iframe') ? item.trim() : item }).join(aLink[i]);
} }
return text; return text;
@@ -226,6 +305,7 @@ const Notifications = {
const bookedProfile = subscribed[index]; const bookedProfile = subscribed[index];
if (bookedProfile._id == senderProfile._id) return 0; if (bookedProfile._id == senderProfile._id) return 0;
const notifBody = `${senderProfile.profile.firstName} commented in a post you follow`; const notifBody = `${senderProfile.profile.firstName} commented in a post you follow`;
sendPushNotification(bookedProfile.token, notifBody, {});
DB.addNotification(bookedProfile._id, notifBody, post._id, post.comments.length - 1); DB.addNotification(bookedProfile._id, notifBody, post._id, post.comments.length - 1);
yourBookmarkedPostGotACommentTemplate(post, userEmail, postProfile, senderProfile, bookedProfile, message); yourBookmarkedPostGotACommentTemplate(post, userEmail, postProfile, senderProfile, bookedProfile, message);
}); });
@@ -241,6 +321,7 @@ const Notifications = {
} }
if (postProfile.isCourse || senderProfile._id == postProfile._id) return 0; //Course owners do not need to receive notifs if (postProfile.isCourse || senderProfile._id == postProfile._id) return 0; //Course owners do not need to receive notifs
const notifBody = `${senderProfile.profile.firstName} commented in your post`; const notifBody = `${senderProfile.profile.firstName} commented in your post`;
sendPushNotification(postProfile.token, notifBody, {});
DB.addNotification(post.profileid, notifBody, postId, post.comments.length - 1); DB.addNotification(post.profileid, notifBody, postId, post.comments.length - 1);
return youGotANewPostCommentTemplate(post, userEmail, postProfile, senderProfile, message); return youGotANewPostCommentTemplate(post, userEmail, postProfile, senderProfile, message);
}, },
@@ -258,6 +339,7 @@ const Notifications = {
let userProfile = subscribed[index]; //who is this email sending to let userProfile = subscribed[index]; //who is this email sending to
if (userProfile._id == senderProfile._id) return 0; //avoid sending self notifications if (userProfile._id == senderProfile._id) return 0; //avoid sending self notifications
const notifBody = `${senderProfile.profile.firstName} post in the group ${groupProfile.profile.firstName} ${groupProfile.profile.lastName}`; const notifBody = `${senderProfile.profile.firstName} post in the group ${groupProfile.profile.firstName} ${groupProfile.profile.lastName}`;
sendPushNotification(userProfile.token, notifBody, {});
DB.addNotification(userProfile._id, notifBody, post._id); DB.addNotification(userProfile._id, notifBody, post._id);
yourGroupGotANewPostTemplate(groupProfile, userEmail, userProfile, senderProfile, message); yourGroupGotANewPostTemplate(groupProfile, userEmail, userProfile, senderProfile, message);
}); });
@@ -270,20 +352,21 @@ const Notifications = {
const profile = await DB.getProfileCache(toProfileId); const profile = await DB.getProfileCache(toProfileId);
const user = await DB.getUserById(profile.userid); const user = await DB.getUserById(profile.userid);
const senderProfile = await DB.getProfileCache(whoPostedId); const senderProfile = await DB.getProfileCache(whoPostedId);
if(profile.isGroup) { if (profile.isGroup) {
return this.yourGroupGotANewPost(profile, senderProfile, message, post); return this.yourGroupGotANewPost(profile, senderProfile, message, post);
} }
if(post.nonOrganicType == 'News'){ if (post.nonOrganicType == 'News') {
const emails = await DB.getAllEmails(); const emails = await DB.getAllEmails();
return this.broadcastNews(post, emails); return this.broadcastNews(post, emails);
} }
const notifBody = `${senderProfile.profile.firstName} post in your profile`; const notifBody = `${senderProfile.profile.firstName} post in your profile`;
sendPushNotification(profile.token, notifBody, {});
DB.addNotification(toProfileId, notifBody, post._id); DB.addNotification(toProfileId, notifBody, post._id);
return youGotANewPostTemplate(profile, user.username, senderProfile, message); return youGotANewPostTemplate(profile, user.username, senderProfile, message);
}, },
youHaveAnInvitation, youHaveAnInvitation,
broadcastNews, broadcastNews,
async yourGroupHasARequest(requesterProfileId, groupId){ async yourGroupHasARequest(requesterProfileId, groupId) {
const DB = await DBGetter.getDB; const DB = await DBGetter.getDB;
const requesterProfile = await DB.getProfileCache(requesterProfileId); const requesterProfile = await DB.getProfileCache(requesterProfileId);
const groupProfile = await DB.getProfileCache(groupId); const groupProfile = await DB.getProfileCache(groupId);

29
package-lock.json generated
View File

@@ -14,6 +14,7 @@
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"expo-server-sdk": "^3.6.0",
"express": "^4.17.1", "express": "^4.17.1",
"mongodb": "^3.6.3", "mongodb": "^3.6.3",
"nodemailer": "^6.6.3", "nodemailer": "^6.6.3",
@@ -378,6 +379,15 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/expo-server-sdk": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/expo-server-sdk/-/expo-server-sdk-3.6.0.tgz",
"integrity": "sha512-GyA0BTcFBKk/5gTEO4WOScP9hEttR+GitrcOIl7XwXwE1FHFvbluKiUc9yEjsfEYMgyd78+XhSpGVGQnutGOdA==",
"dependencies": {
"node-fetch": "^2.6.0",
"promise-limit": "^2.7.0"
}
},
"node_modules/express": { "node_modules/express": {
"version": "4.17.1", "version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
@@ -973,6 +983,11 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
}, },
"node_modules/promise-limit": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz",
"integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="
},
"node_modules/proper-lockfile": { "node_modules/proper-lockfile": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-2.0.1.tgz", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-2.0.1.tgz",
@@ -1627,6 +1642,15 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
}, },
"expo-server-sdk": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/expo-server-sdk/-/expo-server-sdk-3.6.0.tgz",
"integrity": "sha512-GyA0BTcFBKk/5gTEO4WOScP9hEttR+GitrcOIl7XwXwE1FHFvbluKiUc9yEjsfEYMgyd78+XhSpGVGQnutGOdA==",
"requires": {
"node-fetch": "^2.6.0",
"promise-limit": "^2.7.0"
}
},
"express": { "express": {
"version": "4.17.1", "version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
@@ -2079,6 +2103,11 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
}, },
"promise-limit": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz",
"integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="
},
"proper-lockfile": { "proper-lockfile": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-2.0.1.tgz", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-2.0.1.tgz",

View File

@@ -15,6 +15,7 @@
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"expo-server-sdk": "^3.6.0",
"express": "^4.17.1", "express": "^4.17.1",
"mongodb": "^3.6.3", "mongodb": "^3.6.3",
"nodemailer": "^6.6.3", "nodemailer": "^6.6.3",