[text] backup

Viewer

  1.  
  2. const functions = require('firebase-functions');
  3. const admin = require('firebase-admin');
  4. const express = require('express');
  5. const cors = require('cors');
  6. const app = express();
  7.  
  8. const _ = require('lodash');
  9.  
  10. app.use(cors({ origin: true }));
  11.  
  12. app.get('/hello-world', (req, res) => {
  13.   return res.status(200).send('Hello World!');
  14. });
  15.  
  16. app.post('/api/sendSensorData', (req, res) => {
  17.   (async () => {
  18.       try {
  19.         const sensorBody = {
  20.           deviceID: req.body.deviceID,
  21.           dateCreated: new Date(),
  22.           batteryState: req.body.batteryState,
  23.           temp: req.body.temp,
  24.          moisture: req.body.moisture,
  25.         humidity: req.body.humidity,
  26.        light: req.body.light
  27.       }
  28.         await db.collection('SensorData').add(sensorBody);
  29.            
  30.         return res.status(200).send(`Sent sensor data from ${req.body.deviceID}`);
  31.       } catch (error) {
  32.         console.log(error);
  33.         return res.status(500).send(error);
  34.       }
  35.     })();
  36. });
  37.  
  38. exports.app = functions.https.onRequest(app);
  39.  
  40. var serviceAccount = require("./permissions.json");
  41. admin.initializeApp({
  42.   credential: admin.credential.cert(serviceAccount),
  43.   storageBucket: 'gs://flora-85fce.appspot.com',
  44. });
  45.  
  46. // MARK: Test Production
  47. // admin.initializeApp({
  48. //   credential: admin.credential.cert(serviceAccount)
  49.   //storageBucket: 'gs://flora-test-63309.appspot.com',
  50. // });
  51.  
  52. const db = admin.firestore();
  53.  
  54. exports.sendDailyReminder = functions.firestore
  55. .document('/UserReminders/{documentId}')
  56. .onCreate((snap, context) => {
  57.  
  58.     const reminderId = context.params.documentId;
  59.  
  60.     const data = snap.data();
  61.  
  62.     // access a particular field as you would any JS property
  63.     const plantName = data.plantName;
  64.  
  65.     console.log('We have a new Reminder:', reminderId);
  66.     console.log('Checking value of plantName:', plantName);
  67.      // Notification details.
  68.      const payload = {
  69.         notification: {
  70.           title: 'You have a plant to save!',
  71.           body: `Your ${plantName} needs some water - make sure to take care of it!`,
  72.           badge: '1'
  73.         }
  74.       };
  75.       console.log(payload)
  76.  
  77.       admin.messaging().sendToDevice(registrationTokens, payload)
  78.       .then(function(response) {
  79.         // See the MessagingDevicesResponse reference documentation for
  80.         // the contents of response.
  81.         console.log('Successfully sent message:', response);
  82.       })
  83.       .catch(function(error) {
  84.         console.log('Error sending message:', error);
  85.       });
  86.   });
  87.  
  88. exports.sendFollowerNotification = functions.firestore.document('/Users/{followedUid}/followers/{followerUid}')
  89. .onCreate((snap, context) => {
  90.     
  91.     const data = snap.data();
  92.  
  93.     const token = data.userFCMToken
  94.     const followerUsername = data.username;
  95.     const userPicture = data.userPic;
  96.  
  97.     const payload = {
  98.       notification: {
  99.         title: 'You have a new plant buddy!',
  100.         body: `${followerUsername} is now following you. ☺️🌱`,
  101.         icon: userPicture,
  102.         badge: '1'
  103.       }
  104.     };
  105.  
  106.     admin.messaging().sendToDevice(token, payload)
  107.     .then(function(response) {
  108.     console.log('Sending following payload:', payload);
  109.     })
  110.     .catch(function(error) {
  111.       console.log('Error sending message:', error);
  112.     });
  113.  
  114.   });
  115.  
  116.   exports.sendLikesNotification = functions.firestore.document('/UserActivity/{userPostId}/likes/{likerUid}')
  117.   .onCreate((snap, context) => {
  118.     const data = snap.data();
  119.  
  120.     const token = data.userFCMToken
  121.     const followerUsername = data.username;
  122.     const userPicture = data.userPic;
  123.     const plantCommonName = data.plantName;
  124.     const plantCommonNickname = data.plantNickname;
  125.     const activity = data.activityType;
  126.  
  127.     var payloadBody = ""
  128.  
  129.     if (activity == "watering") {
  130.       var payloadBody = `${followerUsername} liked that you watered ${plantCommonNickname}! ❤️`
  131.     } else {
  132.       var payloadBody = `${followerUsername} liked that you added ${plantCommonNickname}! ❤️`
  133.     }
  134.     
  135.     const payload = {
  136.       notification: {
  137.         title: `Your ${plantCommonName} is popular!`,
  138.         body: payloadBody,
  139.         icon: userPicture,
  140.         badge: '1'
  141.       }
  142.     };
  143.  
  144.  
  145.     admin.messaging().sendToDevice(token, payload)
  146.     .then(function(response) {
  147.     console.log('Sending following payload:', payload);
  148.     })
  149.     .catch(function(error) {
  150.       console.log('Error sending message:', error);
  151.     });
  152.  
  153.   });
  154.  
  155.  
  156.   exports.sendCommentsNotification = functions.firestore.document('/Comments/{commentId}')
  157.   .onCreate((snap, context) => {
  158.     const data = snap.data();
  159.  
  160.     var token = ""
  161.     var replyTitle = ""
  162.     var payloadBody = ""
  163.  
  164.     const commentUsername = data.username;
  165.     const plantCommonName = data.plantName;
  166.  
  167.     if (!!data.parentCommentUserFCMToken) {
  168.        token = data.parentCommentUserFCMToken  
  169.        replyTitle = `You have a new reply! 🙂`
  170.        payloadBody = `${commentUsername} commented on your reply!`
  171.     } else {
  172.        token = data.postUserFCMToken
  173.        replyTitle = `You have a new comment on your post! 🙂`
  174.  
  175.        if (!!plantCommonName) {
  176.         payloadBody = `${commentUsername} commented on your ${plantCommonName}!`
  177.        } else {
  178.         payloadBody = `${commentUsername} commented on your post!`
  179.        }
  180.     }
  181.  
  182.  
  183.     
  184.     const payload = {
  185.       notification: {
  186.         title: replyTitle,
  187.         body: payloadBody,
  188.         badge: '1'
  189.       }
  190.     };
  191.  
  192.  
  193.     admin.messaging().sendToDevice(token, payload)
  194.     .then(function(response) {
  195.     console.log('Sending following payload:', payload);
  196.     })
  197.     .catch(function(error) {
  198.       console.log('Error sending message:', error);
  199.     });
  200.  
  201.   });
  202.  
  203. //MARK - Old schedule async
  204. // exports.scheduleAsyncMorningNotif = functions.pubsub.schedule('10 08 * * *')
  205. // .timeZone('America/Chicago')
  206. // .onRun((context) => {
  207. //     const tsToMillis = admin.firestore.Timestamp.now().toMillis();
  208. //     const today = new Date(tsToMillis + (15 * 60 * 60 * 1000));
  209.     
  210. //     const userPlants = db.collection('UserPlants');
  211.     
  212. //     let lastVisible = null;
  213. //     let totalSuccessCount = 0;
  214.     
  215. //     function handleUserPlantsFCM() {
  216. //         const snapshot = !!lastVisible ? userPlants.where('nextWatering', '<=', today).where('notificationsEnabled', '==', true).orderBy("nextWatering").startAfter(lastVisible).limit(500).get() 
  217. //         : userPlants.where('nextWatering', '<=', today).where('notificationsEnabled', '==', true).orderBy("nextWatering").limit(500).get();
  218.                         
  219. //         if (snapshot.empty) {
  220. //             console.log('No matching documents.');
  221. //             return;
  222. //         }
  223.     
  224. //         snapshot.then(async function(querySnapshot) {
  225. //             console.log('Query Snapshot of UserPlants showing as:', querySnapshot.size);
  226. //             lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
  227. //             var messages = [];
  228. //             querySnapshot.forEach((doc) => {
  229. //                 const data = doc.data();
  230. //                 const { plantName, userFCMToken } = data;
  231. //                 if (plantName && userFCMToken) {
  232. //                     const message = {
  233. //                         notification: {
  234. //                             title: 'You have a plant to save! 🌱',
  235. //                             body: `Your ${plantName} needs some water - make sure to take care of it! ☔️`,
  236. //                         },
  237. //                         token: userFCMToken
  238. //                     };
  239. //                     messages.push(message);
  240. //                 } else {
  241. //                   console.log('Nil/false on user token, skipping for now');
  242. //                 }
  243. //             });
  244. //             if (!!messages.length) {
  245. //                 try {
  246. //                     const response  = await admin.messaging().sendAll(messages);
  247. //                     totalSuccessCount += response.successCount;
  248. //                 } catch(err) {
  249. //                     console.log(err);
  250. //                 }
  251. //                 messages = [];
  252. //             }
  253.             
  254. //             handleUserPlantsFCM();
  255. //         });
  256. //     }
  257.     
  258. //     handleUserPlantsFCM();
  259. //     console.log(totalSuccessCount + ' messages were sent successfully');
  260.     
  261. //     return null;
  262. // });
  263. // exports.scheduleAsyncMorningNotif = functions.pubsub.schedule('10 08 * * *')
  264. exports.scheduleAsyncMorningNotif = functions.pubsub.schedule('10 08 * * *')
  265.   .timeZone("America/Chicago")
  266.   .onRun((context) => {
  267.     const tsToMillis = admin.firestore.Timestamp.now().toMillis();
  268.     const today = new Date(tsToMillis + 15 * 60 * 60 * 1000);
  269.     const userPlants = db.collection("TestUserPlants");
  270.     var lastVisible = null;
  271.     // let totalSuccessCount = 0;
  272.     var multipleUsers = [];
  273.     function handleUserPlantsFCM() {
  274.       const snapshot = !!lastVisible
  275.         ? userPlants
  276.             .where("nextWatering", "<=", today)
  277.             .where("notificationsEnabled", "==", true)
  278.             .orderBy("nextWatering")
  279.             .startAfter(lastVisible)
  280.             .limit(500)
  281.             .get()
  282.         : userPlants
  283.             .where("nextWatering", "<=", today)
  284.             .where("notificationsEnabled", "==", true)
  285.             .orderBy("nextWatering")
  286.             .limit(500)
  287.             .get();
  288.       if (snapshot.size === 0) {
  289.         console.log("No matching documents.");
  290.         return;
  291.       }
  292.       snapshot.then(querySnapshot => {
  293.         console.log(
  294.           "Query Snapshot of UserPlants showing as:",
  295.           querySnapshot.size
  296.         );
  297.         if (querySnapshot.size === 0) {
  298.           console.log("No matching documents.");
  299.           console.log(
  300.             "*****************************************Sending Messages*************************************************"
  301.           );
  302.           if (!!multipleUsers.length) {
  303.             const matchedMultipleUsers = multipleUsers.filter(
  304.               (plant) => plant.count > 2
  305.             );
  306.             if (!!matchedMultipleUsers.length) {
  307.               const matchedNotifications = matchedMultipleUsers.map(
  308.                 (plant) => ({
  309.                   notification: {
  310.                     title: `You have ${plant.count} plants to water! 🌱 `,
  311.                     body: `Your plants need some water - make sure to take care of them! ☔️`,
  312.                   },
  313.                   token: plant.userFCMToken,
  314.                   data: {
  315.                     body: `Your plants need some water - make sure to take care of them! ☔️`,
  316.                   },
  317.                 })
  318.               );
  319.               if (!!matchedNotifications && matchedNotifications.length) {
  320.                 try {
  321.                   admin
  322.                     .messaging()
  323.                     .sendAll(matchedNotifications)
  324.                     .then((response) => {
  325.                       const multipleSuccessCount = response.successCount;
  326.                       console.log(
  327.                         `${multipleSuccessCount} grouping messages are sent successfully.`
  328.                       );
  329.                       console.log(matchedMultipleUsers.length, matchedNotifications.length);
  330.                     });
  331.                 } catch (err) {
  332.                   console.log(err);
  333.                 }
  334.               } else {
  335.                 console.log("There is no grouping messages to be sent!");
  336.               }
  337.             } else {
  338.               console.log("There are no users who have multiple plants.");
  339.             }
  340.             const matchedOneOrTwoUsers = multipleUsers.filter(
  341.               (plant) => plant.count < 3
  342.             );
  343.             if (!!matchedOneOrTwoUsers.length) {
  344.               const matchedNotifications = matchedOneOrTwoUsers.map(
  345.                 (plant) => ({
  346.                   notification: {
  347.                     title: `You have a plant to save! 🌱 `,
  348.                     body: `Your ${plant.plantName.toString()} plant needs some water - make sure to take care of it! ☔️`,
  349.                   },
  350.                   token: plant.userFCMToken,
  351.                   data: {
  352.                     body: `Your ${plant.plantName.toString()} needs some water - make sure to take care of it! ☔️`,
  353.                   },
  354.                 })
  355.               );
  356.               if (!!matchedNotifications && matchedNotifications.length) {
  357.                 try {
  358.                   admin
  359.                     .messaging()
  360.                     .sendAll(matchedNotifications)
  361.                     .then((response) => {
  362.                       const multipleSuccessCount = response.successCount;
  363.                       console.log(
  364.                         `${multipleSuccessCount} messages are sent successfully.`
  365.                       );
  366.                       console.log(matchedOneOrTwoUsers.length, matchedNotifications.length);
  367.                     });
  368.                 } catch (err) {
  369.                   console.log(err);
  370.                 }
  371.               } else {
  372.                 console.log("There is no any messages to be sent!");
  373.               }
  374.             } else {
  375.               console.log("There is no any user who has a plant.");
  376.             }
  377.           }
  378.           return;
  379.         }
  380.         lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
  381.         // var messages = [];
  382.         querySnapshot.forEach((doc) => {
  383.           const data = doc.data();
  384.           const { plantName, userFCMToken, userRef } = data;
  385.           if (plantName && userFCMToken) {
  386.             // check if user does not exist in multiple users
  387.             if (!multipleUsers.some((plant) => plant.userRef === userRef)) {
  388.               let arr = [];
  389.               const userObj = {
  390.                 userRef: userRef,
  391.                 userFCMToken: userFCMToken,
  392.                 plantName: [plantName],
  393.                 count: 1,
  394.               };
  395.               console.log("==============NewUserPlant", plantName);
  396.               multipleUsers.push(userObj);
  397.             } else {
  398.               const existingUserPlant = multipleUsers.find(
  399.                 (plant) => plant.userRef === userRef
  400.               );
  401.               console.log(
  402.                 "++++++++++++++existingUserPlant:",
  403.                 existingUserPlant.plantName[0]
  404.               );
  405.               let arr = [];
  406.               const updatedUserPlant = {
  407.                 ...existingUserPlant,
  408.                 count: parseInt(existingUserPlant.count) + 1,
  409.                 plantName: Array.isArray(existingUserPlant.plantName)
  410.                   ? existingUserPlant.plantName.push(plantName)
  411.                   : [plantName],
  412.               };
  413.               const updatedMultipleUsers = multipleUsers.map((plant) => {
  414.                 if (plant.userRef === userRef) return updatedUserPlant;
  415.                 else return plant;
  416.               });
  417.               multipleUsers = updatedMultipleUsers;
  418.             }
  419.             
  420.           } else {
  421.             console.log("Nil/false on user token, skipping for now");
  422.           }
  423.         });
  424.         
  425.         handleUserPlantsFCM();
  426.       });
  427.     }
  428.     
  429.     return handleUserPlantsFCM();
  430.   });
  431.  
  432. // exports.scheduleAsyncMorningNotif = functions.pubsub.schedule('10 08 * * *')
  433. //   .timeZone('America/Chicago')
  434. //   .onRun((context) => {
  435. //     const tsToMillis = admin.firestore.Timestamp.now().toMillis();
  436. //     const today = new Date(tsToMillis + (15 * 60 * 60 * 1000));
  437. // ​
  438. //     const userPlants = db.collection('UserPlants');
  439. // ​
  440. //     let lastVisible = null;
  441. //     let totalSuccessCount = 0;
  442. //     let multipleUsers = [];
  443. // ​
  444. //     function handleUserPlantsFCM() {
  445. //       const snapshot = !!lastVisible ? userPlants.where('nextWatering', '<=', today).where('notificationsEnabled', '==', true)
  446. //       .orderBy("nextWatering").startAfter(lastVisible).limit(500).get()
  447. //         : userPlants.where('nextWatering', '<=', today).where('notificationsEnabled', '==', true).orderBy("nextWatering").limit(500).get();
  448. // ​
  449. //       if (snapshot.empty) {
  450. //         console.log('No matching documents.');
  451. //         return;
  452. //       }
  453. // ​
  454. //       snapshot.then(async function (querySnapshot) {
  455. //         console.log('Query Snapshot of UserPlants showing as:', querySnapshot.size);
  456. //         lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
  457. //         querySnapshot.forEach((doc) => {
  458. //           const data = doc.data();
  459. //           const { plantName, userFCMToken, userRef } = data;
  460. // ​
  461. //           if (plantName && userFCMToken) {
  462. // ​
  463. //             // check if user does not exist in multiple users
  464. //             if (!multipleUsers.some((plant) => plant.userRef === userRef)) {
  465. //               const userObj = {
  466. //                 userRef: userRef,
  467. //                 userFCMToken: userFCMToken,
  468. //                 plantName: [plantName],
  469. //                 count: 1
  470. //               };
  471. //               multipleUsers.push(userObj);
  472. //             } else {
  473. //               const existingUserPlant = multipleUsers.find((plant) => plant.userRef === userRef)
  474. //               const updatedUserPlant = { ...existingUserPlant, count: parseInt(existingUserPlant.count) + 1, plantName: existingUserPlant.plantName.push(plantName) }
  475. //               const updatedMultipleUsers = multipleUsers.map(plant => {
  476. //                 if (plant.userRef === userRef) return updatedUserPlant
  477. //                 else return plant
  478. //               })
  479. //               multipleUsers = updatedMultipleUsers;
  480. //             }
  481.             
  482. //           } else {
  483. //             console.log('Nil/false on user token, skipping for now');
  484. //           }
  485. //         });        
  486. // ​
  487. //         handleUserPlantsFCM();
  488. //       });
  489. //     }
  490. // ​
  491. //     handleUserPlantsFCM();
  492. //     // console.log(totalSuccessCount + ' messages were sent successfully');
  493. // ​
  494. //     if (!!multipleUsers.length) {
  495. //       const matchedMultipleUsers = multipleUsers.filter((plant) => plant.count > 1);
  496. //       if (!!matchedMultipleUsers.length) {
  497. //         const matchedNotifications = matchedMultipleUsers.map((plant) => ({
  498. //           notification: {
  499. //             title: `You have ${plant.count} plants to water! 🌱 `,
  500. //             body: `Your ${plant.plantName.toString()} needs some water - make sure to take care of it! ☔️`,
  501. //           },
  502. //           token: plant.userFCMToken
  503. //         }));
  504. //         if (!!matchedNotifications && matchedNotifications.length) {
  505. //           try {
  506. //             admin.messaging().sendAll(matchedNotifications).then(response => {
  507. //               const multipleSuccessCount = response.successCount;
  508. //               console.log(`${multipleSuccessCount} grouping messages are sent successfully.`)
  509. //             });
  510. //           } catch (err) {
  511. //             console.log(err);
  512. //           }
  513. //         } else {
  514. //           console.log('There is no any grouping messages to be sent!')
  515. //         }
  516. //       } else {
  517. //         console.log('There is no any user who has multiple plants.');
  518. //       }
  519. //     }
  520. // ​
  521. //     return null;
  522. //   });
  523.  
  524. exports.scheduleEveningNotif = functions.pubsub.schedule('05 18 * * *')
  525. .timeZone('America/Chicago')
  526. .onRun(async (context) => {
  527.     const tsToMillis = admin.firestore.Timestamp.now().toMillis();
  528.     const today = new Date(tsToMillis + (8 * 55 * 60 * 1000));
  529.     
  530.     const userPlants = db.collection('UserPlants');
  531.     
  532.     let lastVisible = null;
  533.     let totalSuccessCount = 0;
  534.     
  535.     async function handleFCMToken() {
  536.         const snapshot = !!lastVisible ? userPlants.where('nextWatering', '<=', today).where('notificationsEnabled', '==', true).orderBy("nextWatering").startAfter(lastVisible).limit(500) 
  537.         : userPlants.where('nextWatering', '<=', today).where('notificationsEnabled', '==', true).orderBy("nextWatering").limit(500);
  538.         
  539.         const querySnapshot = await snapshot.get();
  540.         
  541.         if (querySnapshot.size === 0) {
  542.             console.log('No matching documents.');
  543.             return;
  544.         }
  545.         
  546.         console.log('Query Snapshot of UserPlants showing as:', querySnapshot.size);
  547.         
  548.         lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
  549.         var messages = [];
  550.         
  551.         querySnapshot.forEach((doc) => {
  552.             const data = doc.data();
  553.             const { plantName, userFCMToken } = data;
  554.             if (!!plantName && !!userFCMToken) {
  555.                 const message = {
  556.                     notification: {
  557.                         title: 'You have a plant to save! 🌱',
  558.                         body: `Your ${plantName} needs some water - make sure to take care of it! ☔️`,
  559.                     },
  560.                     token: userFCMToken
  561.                 };
  562.                 messages.push(message);
  563.             } else {
  564.               console.log('Nil/false on user token, skipping for now');
  565.             }
  566.         });
  567.         if (!!messages.length) {
  568.             try {
  569.                 const response  = await admin.messaging().sendAll(messages);
  570.                 totalSuccessCount += response.successCount;
  571.             } catch(err) {
  572.                 console.log(err);
  573.                 return;
  574.             }
  575.         }
  576.         await handleFCMToken();
  577.     }
  578.     
  579.     await handleFCMToken();
  580.     console.log(totalSuccessCount + ' messages were sent successfully');
  581.     return;
  582. });
  583.  
  584. exports.sendFeedbackNotification = functions.firestore.document('/UserFeedback/{feedbackId}')
  585. .onCreate((snap, context) => {
  586.   const data = snap.data();
  587.  
  588.   const token = data.userFCMToken
  589.   const followerUsername = data.username;
  590.   const userPicture = data.userPic;
  591.   const plantCommonName = data.plantName;
  592.   const plantCommonNickname = data.plantNickname;
  593.   const activity = data.activityType;
  594.  
  595.   var payloadBody = ""
  596.  
  597.   if (activity == "watering") {
  598.     var payloadBody = `${followerUsername} liked that you watered ${plantCommonNickname}! ❤️`
  599.   } else {
  600.     var payloadBody = `${followerUsername} liked that you added ${plantCommonNickname}! ❤️`
  601.   }
  602.   
  603.   const payload = {
  604.     notification: {
  605.       title: `Your ${plantCommonName} is popular!`,
  606.       body: payloadBody,
  607.       icon: userPicture,
  608.       badge: '1'
  609.     }
  610.   };
  611.  
  612.  
  613.   admin.messaging().sendToDevice(token, payload)
  614.   .then(function(response) {
  615.   console.log('Sending following payload:', payload);
  616.   })
  617.   .catch(function(error) {
  618.     console.log('Error sending message:', error);
  619.   });
  620.  
  621. });
  622. // exports.runStats = functions.pubsub.schedule('02 08 * * *')
  623. //   .timeZone('America/Chicago')
  624. //   .onRun((context) => {
  625. //     const userPlants = db.collection('UserPlants')
  626. //     const users = db.collection('Users')
  627. //     const plantsSnapshot = userPlants.get();
  628. //     const usersSnapshot = users.get();
  629.  
  630. // if (plantsSnapshot.empty) {
  631. //   console.log('No matching documents.');
  632. //   return;
  633. // }
  634.  
  635. //   plantsSnapshot.then(async function(querySnapshot) {
  636. //     console.log('Query Snapshot of UserPlants showing as:', querySnapshot.size);
  637. //   });
  638.  
  639. //     if (usersSnapshot.empty) {
  640. //       console.log('No matching documents.');
  641. //       return;
  642. //     }
  643.      
  644. //       usersSnapshot.then(async function(querySnapshot) {
  645. //         console.log('Query Snapshot of Users showing as:', querySnapshot.size);
  646. //       });
  647.  
  648. // return null;
  649. // });

Editor

You can edit this paste and save as new:


File Description
  • backup
  • Paste Code
  • 22 Jun-2021
  • 23.15 Kb
You can Share it: