const nodemailer = require("nodemailer"); 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) => { let transporter = nodemailer.createTransport({ host: "mail.emmint.com", port: 465, secure: true, auth: { user: "noreply@emmint.com", pass: process.env.EMAILPASS, }, }); let info = await transporter.sendMail({ from: '"EMI Social" { let subject = senderProfile.profile.firstName + " commented on the post you follow"; let html = `

Hello ${bookedProfile.profile.firstName},

One of the post you bookmarked has a new comment:

${post.content}

— ${postProfile.profile.firstName} ${postProfile.profile.lastName}

Comment:

${message}

— ${senderProfile.profile.firstName} ${senderProfile.profile.lastName}

Check it on the site

Blessings

`; sendEmail(userEmail, subject, html); }; const youGotANewPostCommentTemplate = (post, userEmail, profile, senderProfile, message) => { let subject = senderProfile.profile.firstName + " comment on your post"; let html = `

Hello ${profile.profile.firstName},

You got a comment on your post:

${post.content}

— You

Comment:

${message}

— ${senderProfile.profile.firstName} ${senderProfile.profile.lastName}

Check it on the site

Blessings

`; return sendEmail(userEmail, subject, html); }; const yourGroupGotANewPostTemplate = (groupProfile, userEmail, profile, senderProfile, message) => { let subject = senderProfile.profile.firstName + " posted on one of the groups you follow"; let html = `

Hello ${profile.profile.firstName},

${groupProfile.profile.firstName} ${groupProfile.profile.lastName} have new post:

${message}

— ${senderProfile.profile.firstName} ${senderProfile.profile.lastName}

Check it on the site

Blessings

`; return sendEmail(userEmail, subject, html); }; const youGotANewPostTemplate = (profile, userEmail, senderProfile, message) => { let subject = senderProfile.profile.firstName + " post on your profile"; let html = `

Hello ${profile.profile.firstName},

You got a new post:

${message}

— ${senderProfile.profile.firstName} ${senderProfile.profile.lastName}

Check it on the site

Blessings

`; sendEmail(userEmail, subject, html) } const youHaveAnInvitation = (invitedName, invitedEmail, senderProfile) => { let subject = senderProfile.profile.firstName + " post on your profile"; let html = `

Hello ${invitedName},

You have been invited to be part of the new efforts to be connected through our website.

The social part of our site is a place to be in contact with the espiritual family, read what is new for all the members and have access to the most recent teachings, as well as our catalog of courses.

Register to make an account at https://social.emmint.com/

Invitation sent by: ${senderProfile.profile.firstName} ${senderProfile.profile.lastName}

Blessings

Emmanuel International Ministries

`; sendEmail(invitedEmail, subject, html) } const yourGroupHasARequestTemplate = (groupProfile, ownerEmail, senderProfile) => { let subject = senderProfile.profile.firstName + " wants to join " + groupProfile.profile.firstName + groupProfile.profile.lastName; let html = `

Hello Admin of ${groupProfile.profile.firstName} ${groupProfile.profile.lastName},

Your group, has a new request from ${senderProfile.profile.firstName} ${senderProfile.profile.lastName}

To respond to this request go to the group

Blessings

Emmanuel International Ministries

`; sendEmail(ownerEmail, subject, html) } const yourGroupRequestAcceptedTemplate = (groupProfile, acceptedEmail, acceptedProfile) => { let subject = "Welcome to the " + groupProfile.profile.firstName + " " + groupProfile.profile.lastName + " group"; let html = `

Hello ${acceptedProfile.profile.firstName} ${acceptedProfile.profile.lastName},

Your request to the group ${groupProfile.profile.firstName + groupProfile.profile.lastName} has been accepted.

You can now go to the group

Blessings

Emmanuel International Ministries

`; sendEmail(acceptedEmail, subject, html) } const convertLinks = (input) => { let text = input; const linksFound = text.match(/(?:www|https?)[^\s]+/g); const aLink = []; if (linksFound != null) { for (let i = 0; i < linksFound.length; i++) { let replace = linksFound[i]; if (!(linksFound[i].match(/(http(s?)):\/\//))) { replace = 'http://' + linksFound[i] } let linkText = replace.split('/')[2]; if (linkText.substring(0, 3) == 'www') { linkText = linkText.replace('www.', '') } if (linkText.match(/youtu/)) { let youtubeID = replace.split('/').slice(-1)[0]; aLink.push('
') } else if (linkText.match(/vimeo/)) { let vimeoID = replace.split('/').slice(-1)[0]; aLink.push('
') } else { aLink.push('' + linkText + ''); } text = text.split(linksFound[i]).map(item => { return aLink[i].includes('iframe') ? item.trim() : item }).join(aLink[i]); } return text; } else { return input; } } const broadcastNews = async (post, users) => { let subject = "We have news for you!"; let filteredContent = convertLinks(post.content); let html = `

Hello beloved,

We have news for you:

${filteredContent}

— Emmanuel International Ministries

Check more updates on the website

Blessings

`; for (const user of users) { console.log(user, 'Sending news') await sendEmail(user.username, subject, html); } }; const Notifications = { sendEmail, async yourBookmarkedPostGotAComment(post, postProfile, senderProfile, message) { const DB = await DBGetter.getDB; const subscribedPromise = post.bookmarks.map((profileid) => { return DB.getProfileCache(profileid); }); const subscribed = await Promise.all(subscribedPromise); const usersPromise = subscribed.map((profile) => { return DB.getUsernameByIdCache(profile.userid); }); const usersEmails = await Promise.all(usersPromise); usersEmails.forEach((userEmail, index) => { const bookedProfile = subscribed[index]; if (bookedProfile._id == senderProfile._id) return 0; 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, senderProfile._id); yourBookmarkedPostGotACommentTemplate(post, userEmail, postProfile, senderProfile, bookedProfile, message); }); }, async youGotANewPostComment(postId, whoPostedId, message) { const DB = await DBGetter.getDB; const post = await DB.getPost(postId); const postProfile = await DB.getProfileCache(post.profileid); const senderProfile = await DB.getProfileCache(whoPostedId); const userEmail = await DB.getUsernameByIdCache(postProfile.userid); if (post.bookmarks) { this.yourBookmarkedPostGotAComment(post, postProfile, senderProfile, message) } 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`; sendPushNotification(postProfile.token, notifBody, {}); DB.addNotification(post.profileid, notifBody, postId, post.comments.length - 1, senderProfile._id); return youGotANewPostCommentTemplate(post, userEmail, postProfile, senderProfile, message); }, async yourGroupGotANewPost(groupProfile, senderProfile, message, post) { const DB = await DBGetter.getDB; let subscribedPromise = Object.keys(groupProfile.subscribed).map((profileid) => { return DB.getProfileCache(profileid); }); let subscribed = await Promise.all(subscribedPromise); let usersPromise = subscribed.map((profile) => { return DB.getUsernameByIdCache(profile.userid); }); let users = await Promise.all(usersPromise); users.forEach((userEmail, index) => { let userProfile = subscribed[index]; //who is this email sending to 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}`; sendPushNotification(userProfile.token, notifBody, {}); DB.addNotification(userProfile._id, notifBody, post._id, null, senderProfile._id); yourGroupGotANewPostTemplate(groupProfile, userEmail, userProfile, senderProfile, message); }); }, async youGotANewPost(post) { const toProfileId = post.toProfile; const whoPostedId = post.profileid; const message = post.content; const DB = await DBGetter.getDB; const profile = await DB.getProfileCache(toProfileId); const user = await DB.getUserById(profile.userid); const senderProfile = await DB.getProfileCache(whoPostedId); if (profile.isGroup) { return this.yourGroupGotANewPost(profile, senderProfile, message, post); } if (post.nonOrganicType == 'News') { const emails = await DB.getAllEmails(); return this.broadcastNews(post, emails); } const notifBody = `${senderProfile.profile.firstName} post in your profile`; sendPushNotification(profile.token, notifBody, {}); DB.addNotification(toProfileId, notifBody, post._id, null, senderProfile._id); return youGotANewPostTemplate(profile, user.username, senderProfile, message); }, youHaveAnInvitation, broadcastNews, async yourGroupHasARequest(requesterProfileId, groupId) { const DB = await DBGetter.getDB; const requesterProfile = await DB.getProfileCache(requesterProfileId); const groupProfile = await DB.getProfileCache(groupId); const user = await DB.getUserById(groupProfile.userid); yourGroupHasARequestTemplate(groupProfile, user.username, requesterProfile) }, async yourGroupRequestAccepted(requesterProfileId, groupId) { const DB = await DBGetter.getDB; const requesterProfile = await DB.getProfileCache(requesterProfileId); const groupProfile = await DB.getProfileCache(groupId); const user = await DB.getUserById(requesterProfile.userid); yourGroupRequestAcceptedTemplate(groupProfile, user.username, requesterProfile) } } module.exports = Notifications