Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import axios from 'axios'
- import firebase from 'firebase-admin'
- import usersServices from '../users/services'
- import logger from '@/logger'
- import {
- chunk,
- uniqBy
- } from 'lodash'
- import Bluebird from 'bluebird'
- const FIRESTORE_WRITES_LIMIT_PER_REQUEST = 499
- export default new class {
- /**
- *
- * @typedef {Object} Notification
- * @property {String} notification.title Notification title
- * @property {String} notification.body Notification body
- * @property {Number} notification.post_id Post id
- * @property {Date} notification.publication_time Notification publication time
- */
- /**
- * @description creates a notification and send to users in userIds array
- * @param {import('express').Request} req
- * @param {Notification} notification
- * @param {Array<Integer>} usersIds
- */
- async createNotification (db, orgSlug, firestore, notification, usersIds) {
- try {
- if (!usersIds || usersIds.length === 0) {
- return null
- }
- const devices = await usersServices.getDevices(db, usersIds)
- await this.queueNotification(orgSlug, firestore, devices, notification)
- } catch (err) {
- console.error(err)
- }
- }
- async _addToQueue (devices, notifyData, firestore, organizationSlug) {
- if (devices && devices.length) {
- logger.debug(`Recipients users to notification ${devices.length}`)
- await Bluebird.map(chunk(devices, FIRESTORE_WRITES_LIMIT_PER_REQUEST), async chunkDevices => {
- const batch = firestore.batch()
- chunkDevices.forEach(device => {
- // Onde notificações push são enviadas
- const data = {
- ...notifyData,
- token: device.push_token,
- userUUID: device.uuid || null,
- userUid: `${organizationSlug}-${device.user_id}`,
- status: 'queued'
- }
- const doc = firestore.collection('notification_queue').doc()
- batch.create(doc, data)
- })
- await batch.commit()
- }, {
- concurrency: 2
- })
- }
- }
- async _addToUsers (recipients, devices, notifyData, firestore, organizationSlug) {
- if (recipients === null) {
- recipients = devices
- }
- logger.debug(`Recipients users to notification ${recipients.length}`)
- await Bluebird.map(chunk(recipients, FIRESTORE_WRITES_LIMIT_PER_REQUEST), async chunkRecipients => {
- const batch = firestore.batch()
- // Onde notificações são listadas no frontend
- uniqBy(chunkRecipients, 'id').forEach(user => {
- const data = {
- ...notifyData,
- userUUID: user.uuid || null,
- userUid: `${organizationSlug}-${user.id}`,
- status: 'unread'
- }
- const doc = firestore.collection('notification_users').doc()
- batch.create(doc, data)
- })
- await batch.commit()
- }, {
- concurrency: 2
- })
- }
- /**
- *
- * @param {import('@/middlewares/organization').default} db
- * @param {*} usersIds
- * @param {{
- * channelType: String,
- * eventType: String
- * }} event {{channelType: 'web', eventType: 'post_created'}}
- */
- async getUsersToNotify (db, usersIds, { channelType, eventType }) {
- const allConfigs = await db.UsersNotificationsSettings.findAll({
- where: {
- userId: usersIds
- }
- })
- const recipientsFilteredByConfigs = usersIds.filter(userId => {
- const foundConfigs = allConfigs.find(config => config.userId === userId)
- if (!foundConfigs) {
- return true
- }
- if (foundConfigs.notifyOnNewPost) {
- // .. lógica pra checar se baseado nas configs deve receber notificação
- }
- })
- return recipientsFilteredByConfigs
- }
- /**
- * @description Put a notification on queue
- * @param {string} organizationSlug
- * @param {import('firebase-admin').firestore.Firestore} firestore
- * @param {Array} tokens Users devices tokens
- * @param {Notification} notification
- * @param {{
- * channelType: String,
- * eventType: String
- * }} event {{channelType: 'web', eventType: 'post_created'}}
- */
- async queueNotification (organizationSlug, firestore, devices, notification, allUsers = null, { channelType = ['email', 'push_notification'], eventType = null } = {}) {
- const isDevelopmentEnviroment = process.env.NODE_ENV !== 'production' || process.env.DATABASE_PORT
- if (isDevelopmentEnviroment) {
- return null
- }
- const { recipientsByMail, devicesByPushNotification } = this.getUsersToNotify(db, allUsers, devices, { })
- logger.profile('notifications/services', 'queueNotification')
- // serverTimestamp count as write in cost also in request rating limit (500 writes per request), so whe are in server side is secure to use new Date
- // const now = firebase.firestore.FieldValue.serverTimestamp()
- const now = new Date()
- let publicationTime = now
- if (notification.publication_time && notification.publication_time instanceof Date) {
- logger.debug('notifications/services queueNotification Publication time:', notification.publication_time)
- publicationTime = notification.publication_time
- } else {
- logger.error('notifications/services', `queueNotification', 'Invalid publication time got: ${notification.publication_time}, setting to now`)
- }
- const notifyData = {
- created_at: now,
- updated_at: now,
- deleted_at: null,
- publication_time: publicationTime,
- env: process.env.NODE_ENV,
- organization_slug: organizationSlug,
- title: notification.title || null,
- body: notification.body || null,
- post_id: notification.post_id || null,
- meta: notification.meta || null,
- task_name: null
- }
- await Promise.all([
- // Enviar notificações de email (Enviada por email de usuário)
- this._addToQueueMail(recipientsByMail, notifyData, firestore, organizationSlug),
- // Envia notificações push notifications (Enviada por dispositivos)
- this._addToQueue(devicesByPushNotification, notifyData, firestore, organizationSlug),
- // Notificação do sistema Quoti (Aquelas que aparecem no sininho de notificações)
- this._addToUsers(allUsers, devices, notifyData, firestore, organizationSlug)
- ])
- logger.profile('notifications/services', 'queueNotification')
- }
- /**
- *
- * @param {string} orgSlug
- * @param {firebase.firestore} firestore
- * @param {string} postId
- */
- async deleteNotifications (orgSlug, firestore, postId) {
- // Get notifications on firestore
- const notificationQueueQuery = firestore.collection('notification_queue')
- .where('env', '==', process.env.NODE_ENV)
- .where('organization_slug', '==', orgSlug)
- .where('post_id', '==', postId)
- .where('status', '==', 'scheduled')
- .where('deleted_at', '==', null)
- logger.debug('posts', 'delete', 'Getting notification queue on firestore')
- const notificationQueue = await notificationQueueQuery.get()
- logger.debug('posts', 'delete', 'Getting tasks names')
- // Get notifications tasks names
- const tasks = []
- notificationQueue.forEach(snap => {
- const data = snap.data()
- tasks.push({
- name: data.task_name
- })
- })
- // logger.debug('posts', 'delete', 'Tasks names got', tasks.map(t => t.name))
- logger.debug('posts', 'delete', 'Deleting notifications tasks')
- // Delete notifications tasks
- try {
- const deleteTaskRes = await axios.post('https://us-central1-beyond-quoti.cloudfunctions.net/deleteTask', {
- tasks
- })
- logger.debug('posts', 'delete', 'Delete tasks function response got', {
- status: deleteTaskRes.status,
- statusText: deleteTaskRes.statusText
- })
- } catch (err) {
- logger.error('posts', 'deleteTasks', 'Error at Deleting notifications tasks')
- }
- // Delete (set deleted_at) notifications on firestore and get tokens
- const deletedDevices = []
- // NotificationQueue só tem notificações caso elas estejam com status scheduled
- // Somente se vieram notificações que estavam agendadas é que se deve criar notificações novamente para o post.
- if (notificationQueue.docs && notificationQueue.docs.length > 0) {
- for (const snap of notificationQueue.docs) {
- const data = snap.data()
- deletedDevices.push({
- push_token: data.token,
- user_id: data.userUid ? (data.userUid.split('-')[1] || null) : null
- })
- logger.info('posts', 'delete', 'Deleting notification on firestore:', snap.id)
- await snap.ref
- .update({
- deleted_at: firebase.firestore.FieldValue.serverTimestamp()
- })
- }
- }
- return {
- deletedDevices
- }
- }
- }()
Advertisement
Add Comment
Please, Sign In to add comment