Advertisement
Guest User

Untitled

a guest
Nov 12th, 2019
600
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.37 KB | None | 0 0
  1. import * as functions from 'firebase-functions';
  2. import * as admin from 'firebase-admin';
  3. import * as moment from 'moment';
  4. const nodemailer = require('nodemailer');
  5.  
  6. const cors = require('cors')({ origin: true });
  7. // import * as firebase from 'firebase';
  8.  
  9. const Firestore = require('@google-cloud/firestore');
  10.  
  11. const db = new Firestore({
  12. projectId: 'envite-f33e1'
  13. });
  14.  
  15. // Start writing Firebase Functions
  16. // https://firebase.google.com/docs/functions/typescript
  17.  
  18. admin.initializeApp();
  19.  
  20. const trackedEventKeys: Array<string> = [
  21. 'app_button_click',
  22. // 'login',
  23. // 'logout',
  24. // 'update_cart',
  25. 'user_joined_chat',
  26. 'new_user',
  27. 'new_invitation',
  28. 'new_chat',
  29. 'chat_deleted',
  30. 'product_submit_order',
  31. // 'chat_opened',
  32. // 'chat_closed',
  33. 'navigate',
  34. 'product_discussed',
  35. // 'product_added_to_cart',
  36. // 'product_removed_from_cart',
  37. 'visit'
  38. ];
  39.  
  40. // const batch = db.batch();
  41.  
  42. // const db = firebase.firestore();
  43. export const processProductEvents = functions.firestore
  44. .document('statistics/{statisticsId}/product/{productId}')
  45. .onWrite((change: any, context: any) => {
  46. const products = db.collection(`statistics/${context.params.statisticsId}/product`)
  47. .orderBy('sessions', 'desc')
  48. .orderBy('discussions', 'desc')
  49. .limit(10);
  50.  
  51. products.get()
  52. .then((snapshot: any) => {
  53. const pArr: any = [];
  54. snapshot.docs.forEach((p: any) => {
  55. pArr.push(p.data())
  56. });
  57.  
  58. db.collection('statistics')
  59. .doc(context.params.statisticsId)
  60. .collection('accumulated')
  61. .doc('product')
  62. .set({
  63. chart_data: pArr
  64. }, { merge: true });
  65.  
  66. console.log('[processProductEvents]')
  67. })
  68.  
  69. return null;
  70. });
  71.  
  72. export const processUserEvents = functions.firestore
  73. .document('statistics/{statisticsId}/users/{userId}')
  74. .onWrite((change: any, context: any) => {
  75. const users = db.collection(`statistics/${context.params.statisticsId}/users`)
  76. .orderBy('registrations', 'desc')
  77. .orderBy('invitations', 'desc')
  78. .limit(10);
  79.  
  80. users.get()
  81. .then((snapshot: any) => {
  82. const uArr: any = [];
  83. snapshot.docs.forEach((p: any) => {
  84. uArr.push({ ...p.data(), id: p.id })
  85. });
  86.  
  87. db.collection('statistics')
  88. .doc(context.params.statisticsId)
  89. .collection('accumulated')
  90. .doc('users')
  91. .set({
  92. chart_data: uArr
  93. }, { merge: true });
  94.  
  95. console.log('[processUsersEvents]')
  96. })
  97.  
  98. return null;
  99. });
  100.  
  101. export const processChatEvents = functions.firestore
  102. .document('statistics/{statisticsId}/chat/{chatId}')
  103. .onWrite((change, context) => {
  104. // Get value of the newly added rating
  105. const afterData = change.after.data();
  106. const beforeData = change.before.data();
  107. const before: boolean = change.before.exists;
  108. const after: boolean = change.after.exists;
  109.  
  110. // Get a reference to the restaurant
  111. const chatRef = db.collection('statistics')
  112. .doc(context.params.statisticsId)
  113. .collection('accumulated')
  114. .doc('chat');
  115.  
  116. // Update aggregations in a transaction
  117. return db.runTransaction((transaction: any) => {
  118. return transaction.get(chatRef).then((chatDoc: any) => {
  119.  
  120. if (before === false && after === true) {
  121. return transaction.set(chatRef, {
  122. total: admin.firestore.FieldValue.increment(1),
  123. opened: admin.firestore.FieldValue.increment(1),
  124. }, { merge: true });
  125. } else if (before === true && after === true && afterData && beforeData) {
  126. if (afterData.openedBy.length === 0 && beforeData.openedBy.length > 0) {
  127. return transaction.set(chatRef, {
  128. total: admin.firestore.FieldValue.increment(0),
  129. opened: admin.firestore.FieldValue.increment(-1),
  130. }, { merge: true });
  131. } else if (afterData.openedBy.length > 0 && beforeData.openedBy.length === 0) {
  132. return transaction.set(chatRef, {
  133. total: admin.firestore.FieldValue.increment(0),
  134. opened: admin.firestore.FieldValue.increment(1),
  135. }, { merge: true });
  136. }
  137. } else if (before === true && after === false && beforeData) {
  138. if (beforeData.openedBy.length > 0) {
  139. return transaction.set(chatRef, {
  140. total: admin.firestore.FieldValue.increment(-1),
  141. opened: admin.firestore.FieldValue.increment(-1),
  142. }, { merge: true });
  143. } else {
  144. return transaction.set(chatRef, {
  145. total: admin.firestore.FieldValue.increment(-1),
  146. opened: admin.firestore.FieldValue.increment(0),
  147. }, { merge: true });
  148. }
  149. } else {
  150. throw new Error(`Unkown firestore event! before: '${before}', after: '${after}'`);
  151. }
  152. });
  153. });
  154. });
  155.  
  156. export const processEvents = functions.firestore
  157. .document('statistics/{statisticsId}/events/{eventId}')
  158. .onWrite((change: any, context: any) => {
  159. const data = change.after.data();
  160. const before: boolean = change.before.exists;
  161. const after: boolean = change.after.exists;
  162.  
  163. let incrementValue: number = 1;
  164. console.log('------------[' + data.key + ']--------------')
  165.  
  166. db.collection('statistics')
  167. .doc(context.params.statisticsId)
  168. .collection('goals')
  169. .where('key', '==', data.key)
  170. .get()
  171. .then((snapshot: any) => {
  172. snapshot.docs.forEach((g: any) => {
  173. db.collection('statistics')
  174. .doc(context.params.statisticsId)
  175. .collection('goals')
  176. .doc(g.id)
  177. .update({
  178. visits: admin.firestore.FieldValue.increment(incrementValue) || incrementValue
  179. });
  180. });
  181. });
  182.  
  183. switch (data.key) {
  184. case 'navigate':
  185. if (!before) {
  186. db.collection('statistics')
  187. .doc(context.params.statisticsId)
  188. .collection('product')
  189. .where('url', '==', data.val.url)
  190. .get()
  191. .then((snapshot: any) => {
  192. snapshot.docs.forEach((p: any) => {
  193. db.collection('statistics')
  194. .doc(context.params.statisticsId)
  195. .collection('product')
  196. .doc(p.id)
  197. .update({
  198. sessions: admin.firestore.FieldValue.increment(incrementValue) || incrementValue
  199. });
  200. });
  201. });
  202. db.collection('statistics')
  203. .doc(context.params.statisticsId)
  204. .collection('goals')
  205. .where('type', '==', 'url')
  206. .where('url', '==', data.val.url)
  207. .get()
  208. .then((snapshot: any) => {
  209. snapshot.docs.forEach((g: any) => {
  210. db.collection('statistics')
  211. .doc(context.params.statisticsId)
  212. .collection('goals')
  213. .doc(g.id)
  214. .update({
  215. visits: admin.firestore.FieldValue.increment(incrementValue) || incrementValue
  216. });
  217. });
  218. });
  219. }
  220. break;
  221. case 'product_discussed':
  222. db.collection('statistics')
  223. .doc(context.params.statisticsId)
  224. .collection('product')
  225. .doc(data.val.productId)
  226. .set({
  227. url: data.val.productUrl,
  228. image: data.val.imgSource,
  229. name: data.val.productName,
  230. discussions: admin.firestore.FieldValue.increment(1),
  231. cost: data.val.productCost
  232. }, { merge: true });
  233. break;
  234. case 'new_invitation':
  235. !before && db.collection('statistics')
  236. .doc(context.params.statisticsId)
  237. .collection('users')
  238. .doc(data.val.referrer)
  239. .set({
  240. invitations: admin.firestore.FieldValue.increment(1),
  241. }, { merge: true });
  242. break;
  243. case 'user_joined_chat':
  244. !before && db.collection('statistics')
  245. .doc(context.params.statisticsId)
  246. .collection('users')
  247. .doc(data.val.referrer)
  248. .set({
  249. registrations: admin.firestore.FieldValue.increment(1),
  250. }, { merge: true });
  251. break;
  252. case 'visit':
  253.  
  254. if (data.user_id && data.val.nonUniqueVisits <= 2) {
  255. db.collection('statistics')
  256. .doc(context.params.statisticsId)
  257. .collection('users')
  258. .doc(data.user_id)
  259. .set({
  260. sessions: admin.firestore.FieldValue.increment(1),
  261. }, { merge: true });
  262. }
  263.  
  264. if (!before) {
  265. db.collection('statistics')
  266. .doc(context.params.statisticsId)
  267. .collection('accumulated')
  268. .doc('visits')
  269. .collection('visits_info')
  270. .doc('devices')
  271. .set({
  272. [data.val.device]: admin.firestore.FieldValue.increment(incrementValue) || incrementValue
  273. }, { merge: true });
  274.  
  275. db.collection('statistics')
  276. .doc(context.params.statisticsId)
  277. .collection('accumulated')
  278. .doc('visits')
  279. .collection('visits_info')
  280. .doc('countries')
  281. .set({
  282. [data.val.country]: admin.firestore.FieldValue.increment(incrementValue) || incrementValue
  283. }, { merge: true });
  284.  
  285. db.collection('statistics')
  286. .doc(context.params.statisticsId)
  287. .collection('accumulated')
  288. .doc('visits')
  289. .collection('visits_info')
  290. .doc('browsers')
  291. .set({
  292. [data.val.browser]: admin.firestore.FieldValue.increment(incrementValue) || incrementValue
  293. }, { merge: true });
  294. }
  295. break;
  296. case 'chat_opened': {
  297. db.collection('statistics')
  298. .doc(context.params.statisticsId)
  299. .collection('chat')
  300. .doc(data.val.chatId)
  301. .set({
  302. creator_id: data.user_id,
  303. name: '',
  304. openedBy: admin.firestore.FieldValue.arrayUnion(data.user_id),
  305. }, { merge: true })
  306.  
  307. console.log('TTTTTTTTTTTTTTTTTTTT', data.website_id, data.val.chatId, data.user_id)
  308.  
  309. db.collection('websites')
  310. .doc(data.website_id)
  311. .collection('chats')
  312. .doc(data.val.chatId)
  313. .set({
  314. openedBy: admin.firestore.FieldValue.arrayUnion(data.user_id),
  315. }, { merge: true })
  316.  
  317. db.collection('websites')
  318. .doc(data.website_id)
  319. .collection('chats')
  320. .doc(data.val.chatId)
  321. .collection("messgaes")
  322. .orderBy("created_at", "desc")
  323. .limit(1)
  324. .get()
  325. .then((messagesArray: any) => {
  326. messagesArray.docs.forEach((message: any) => {
  327. db.collection('websites')
  328. .doc(data.website_id)
  329. .collection('chats')
  330. .doc(data.val.chatId)
  331. .collection("messgaes")
  332. .doc(message.id)
  333. .set({
  334. seen_by: admin.firestore.FieldValue.arrayUnion(data.user_id),
  335. not_seen_by: admin.firestore.FieldValue.arrayRemove(data.user_id),
  336. }, { merge: true })
  337. })
  338. });
  339. }
  340.  
  341. break;
  342. case 'chat_closed': {
  343. db.collection('statistics')
  344. .doc(context.params.statisticsId)
  345. .collection('chat')
  346. .doc(data.val.chatId)
  347. .set({
  348. openedBy: admin.firestore.FieldValue.arrayRemove(data.user_id),
  349. }, { merge: true })
  350.  
  351. db.collection('websites')
  352. .doc(data.website_id)
  353. .collection('chats')
  354. .doc(data.val.chatId)
  355. .set({
  356. openedBy: admin.firestore.FieldValue.arrayRemove(data.user_id),
  357. }, { merge: true })
  358. }
  359. break;
  360. case 'chat_deleted':
  361. db.collection('statistics')
  362. .doc(context.params.statisticsId)
  363. .collection('chat')
  364. .doc(data.val.chatId)
  365. .delete();
  366. break;
  367. case 'product_submit_order':
  368.  
  369. if (!before) {
  370. const total = +data.val.grand_total;
  371. const user_id = data.user_id;
  372. const currency = data.val.currency;
  373. const total_quantity = data.val.total_quantity;
  374. incrementValue = total_quantity;
  375.  
  376. console.log('INCREMENT', incrementValue, user_id)
  377.  
  378. db.collection(`statistics/${context.params.statisticsId}/users`)
  379. .doc(user_id)
  380. .set({
  381. sales: {
  382. [currency]: admin.firestore.FieldValue.increment(total) || total
  383. }
  384. }, { merge: true })
  385. .catch((error: any) => {
  386. console.log('Error updating document:', error);
  387. });
  388.  
  389. const productIdsArr = data.val.items;
  390. for (let k in productIdsArr) {
  391. db.collection(`statistics/${context.params.statisticsId}/product`)
  392. .doc(k)
  393. .set({
  394. total_sales: {
  395. [currency]: admin.firestore.FieldValue.increment(+productIdsArr[k]['price']) || +productIdsArr[k]['price']
  396. },
  397. sales: admin.firestore.FieldValue.increment(productIdsArr[k]['qty']) || productIdsArr[k]['qty']
  398. }, { merge: true })
  399. .catch((error: any) => {
  400. console.log('Error updating document:', error);
  401. });
  402. }
  403.  
  404. db.collection('statistics')
  405. .doc(context.params.statisticsId)
  406. .collection('accumulated')
  407. .doc('product')
  408. .set({
  409. sales: admin.firestore.FieldValue.increment(total_quantity) || total_quantity,
  410. total_sales: {
  411. [currency]: admin.firestore.FieldValue.increment(total) || total
  412. }
  413. }, { merge: true });
  414.  
  415.  
  416. db.collection('websites')
  417. .doc(data.website_id)
  418. .collection('orders')
  419. .add({
  420. currency: data.val.currency,
  421. discount: data.val.discount,
  422. grand_total: data.val.grand_total,
  423. items: data.val.items,
  424. order_id: data.val.order_id,
  425. total_quantity: data.val.total_quantity,
  426. is_read: false,
  427. user_id: user_id,
  428. created_at: moment(Date.now()).valueOf()
  429. })
  430. }
  431.  
  432. break;
  433. default: ;
  434. }
  435.  
  436. if (trackedEventKeys.includes(data.key) && before === false && after === true) {
  437. db.collection('statistics')
  438. .doc(context.params.statisticsId)
  439. .collection('events_accumulated')
  440. .doc(data.key)
  441. .collection('daily_log')
  442. .doc(moment(Date.now()).format("YYYY-MM-DD"))
  443. .set({
  444. [moment(Date.now()).format("YYYY-MM-DD HH:00")]: admin.firestore.FieldValue.increment(incrementValue) || incrementValue
  445. }, { merge: true });
  446. console.log('[' + data.key + ']');
  447. }
  448. return null;
  449. });
  450.  
  451.  
  452. // Create a new function which is triggered on changes to /status/{uid}
  453. // Note: This is a Realtime Database trigger, *not* Cloud Firestore.
  454. export const onUserStatusChanged = functions.database.ref('/status/{combinedId}').onUpdate(
  455. async (change, context) => {
  456. const [uid, websiteId] = context.params.combinedId.split('-');
  457. // Get the data written to Realtime Database
  458. const eventStatus = change.after.val();
  459.  
  460. if (eventStatus.statistics_id && websiteId) {
  461. db.collection('statistics')
  462. .doc(eventStatus.statistics_id)
  463. .collection('chat')
  464. .where('openedBy', 'array-contains', uid)
  465. .get()
  466. .then((snapshot: any) => {
  467. snapshot.docs.forEach((c: any) => {
  468. db.collection('statistics')
  469. .doc(eventStatus.statistics_id)
  470. .collection('chat')
  471. .doc(c.id)
  472. .update({
  473. openedBy: admin.firestore.FieldValue.arrayRemove(uid),
  474. });
  475. });
  476. });
  477.  
  478. db.collection('websites')
  479. .doc(websiteId)
  480. .collection('chats')
  481. .where('openedBy', 'array-contains', uid)
  482. .get()
  483. .then((snapshot: any) => {
  484. snapshot.docs.forEach((c: any) => {
  485. db.collection('websites')
  486. .doc(websiteId)
  487. .collection('chats')
  488. .doc(c.id)
  489. .update({
  490. openedBy: admin.firestore.FieldValue.arrayRemove(uid),
  491. });
  492. });
  493. });
  494. }
  495.  
  496. // Then use other event data to create a reference to the
  497. // corresponding Firestore document.
  498. const userStatusFirestoreRef = db.doc(`user_statuses/${context.params.combinedId}`);
  499.  
  500. // It is likely that the Realtime Database change that triggered
  501. // this event has already been overwritten by a fast change in
  502. // online / offline status, so we'll re-read the current data
  503. // and compare the timestamps.
  504. const statusSnapshot = await change.after.ref.once('value');
  505. const status = statusSnapshot.val();
  506. // If the current timestamp for this data is newer than
  507. // the data that triggered this event, we exit this function.
  508. if (status.last_changed > eventStatus.last_changed) {
  509. return null;
  510. }
  511.  
  512. // Otherwise, we convert the last_changed field to a Date
  513. eventStatus.last_changed = new Date(eventStatus.last_changed);
  514.  
  515. // ... and write it to Firestore.
  516. return userStatusFirestoreRef.set(eventStatus);
  517. });
  518.  
  519.  
  520. export const getGeneratedPasswordResetUrl = functions.https.onRequest((req: any, res: any) => {
  521. const userEmail = 'mamuka.anjaparidze01@gmail.com';
  522. admin.auth().generatePasswordResetLink(userEmail).then((link) => {
  523. console.log("rame data");
  524. // Construct password reset email template, embed the link and send
  525. // using custom SMTP server.
  526. console.log(userEmail, link)
  527.  
  528.  
  529. let transporter = nodemailer.createTransport({
  530. service: 'gmail',
  531. auth: {
  532. user: 'shamatavamariami@gmail.com',
  533. pass: 'ulpisejqkllasggv'
  534. }
  535. });
  536. cors(req, res, () => {
  537.  
  538. // getting dest email by query string
  539. // const dest = req.query.dest;
  540.  
  541. const mailOptions = {
  542. from: 'Your Account Name <yourgmailaccount@gmail.com>', // Something like: Jane Doe <janedoe@gmail.com>
  543. to: 'msham16@freeuni.edu.ge',
  544. subject: 'I\'M A PICKLE!!!', // email subject
  545. // html: `<div style="background:blue; width:300px; height:300px">
  546. // ${link} <p style="font-size: 16px;">Pickle Riiiiiiiiiiiiiiiick!!</p>
  547. // <br />
  548. // <img src="https://images.prod.meredith.com/product/fc8754735c8a9b4aebb786278e7265a5/1538025388228/l/rick-and-morty-pickle-rick-sticker"/>
  549. // <div>`
  550. html: `<div style="width: 500px; height: 100%;">
  551. <div
  552. style="background:blue;width:500px;height:700px;display:flex;justify-content:center;align-items: center;">
  553. <div
  554. style="background:white; width:350px; height: 550px; display: flex; justify-content: center; align-items: center; ">
  555. <h1>FORGOT YOUR PASSWORD?</h1></div>
  556.  
  557. </div>
  558. <div style="display: flex; flex-direction: column; margin-top: -50px;">
  559. <span style="margin: 0 auto;">Email sent by eNvite Team</span>
  560. <span style="margin: 0 auto">Copyright © 2019 eNvite Ltd. All rights reserved.</span>
  561. </div>
  562. </div>`
  563. };
  564.  
  565. // returning result
  566. return transporter.sendMail(mailOptions, (erro: any, info: any) => {
  567. if (erro) {
  568. return res.send(erro.toString());
  569. }
  570.  
  571. return res.send('Sended');
  572. });
  573. });
  574.  
  575. })
  576. .catch((error) => {
  577. // Some error occurred.
  578. console.log(error)
  579. });
  580.  
  581. // res.status(200).send(userEmail);
  582. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement