From 07debfe6930e84f11116bb81d96c703b78ba5048 Mon Sep 17 00:00:00 2001 From: david Date: Mon, 14 Oct 2019 17:25:35 +0200 Subject: [PATCH] . --- core/passport.js | 9 +-- modules/push/push.controller.js | 36 ++++++++++- modules/push/push.routes.js | 16 +++-- modules/push/push.service.js | 101 ++++++++++++++++++++++++++++++- modules/push/push.validations.js | 4 ++ 5 files changed, 151 insertions(+), 15 deletions(-) diff --git a/core/passport.js b/core/passport.js index 8cb0709..a80c5c5 100644 --- a/core/passport.js +++ b/core/passport.js @@ -104,7 +104,7 @@ passport.use('jwt', new CustomStrategy(async (req, done) => { console.log('appVersion: ', appVersion); if (!token) { - //console.log('no tengo token'); + console.error('Unauthorized. Token missing.'); return done(null, false, { message: 'Unauthorized. Token missing.'}); } @@ -123,16 +123,17 @@ passport.use('jwt', new CustomStrategy(async (req, done) => { } } delete user.password; - //console.log('Usuario encontrado', user); + console.log('Logged in Successfully'); return done(null, user, { message: 'Logged in Successfully' }); } else { - //console.log('Usuario no encontrado'); + console.error('Unauthorized. User not found.'); return done(null, false, { message: 'Unauthorized. User not found.' }); } } - else { + else { //console.log('Token no vĂ¡lido'); + console.error('Unauthorized. Invalid token.'); return done(null, false, { message: 'Unauthorized. Invalid token.' }); } diff --git a/modules/push/push.controller.js b/modules/push/push.controller.js index e1b6d31..1b19a20 100644 --- a/modules/push/push.controller.js +++ b/modules/push/push.controller.js @@ -4,6 +4,7 @@ const Sequelize = require('sequelize'); const generateControllers = require('../../core/controllers'); const { buildContext } = require('../../core/controllers'); const pushService = require('./push.service'); +const userService = require('../auth/auth.service'); const { extractParamsFromRequest, handleErrorResponse, handleResultResponse } = require('../../helpers/controller.helper'); // Module Name @@ -11,7 +12,40 @@ const MODULE_NAME = '[push.controller]'; const controllerOptions = { MODULE_NAME }; const extraControllers = { - createOrUpdate: (config) => { + sendNotification: (config) => { + return async (req, res, next) => { + let receipt = undefined; + try { + const context = buildContext(req, config); + let params = extractParamsFromRequest(req, res); + console.log(context, params); + + let token = undefined; + if (params.userId) { + token = await pushService._getPushToken({ + userId: params.userId}); + } + + const message = { + to: token, + sound: 'default', + title: req.body.title, + body: req.body.message, + }; + + receipt = await pushService.sendNotification(message); + + + } catch (error) { + console.error(error); + } finally { + // En todo caso devolver OK al cliente + return handleResultResponse(receipt, null, null, res, httpStatus.OK); + } + } + }, + + registerUser: (config) => { return async (req, res, next) => { try { const context = buildContext(req, config); diff --git a/modules/push/push.routes.js b/modules/push/push.routes.js index e606181..0ac4d91 100644 --- a/modules/push/push.routes.js +++ b/modules/push/push.routes.js @@ -5,24 +5,22 @@ const SchemaValidator = require('../../middlewares/schemaValidator'); const FieldMiddleware = require('../../middlewares/fields'); const pushTokenController = require('./push.controller'); -const { pushInputType } = require('./push.validations'); +const { pushInputType, pushSendType } = require('./push.validations'); const generalInvalidFields = [ 'createdAt', 'updatedAt', ]; -routes.get('/me/pushtoken', - isLoggedUser, - FieldMiddleware.middleware({ - invalidFields: generalInvalidFields - }), - pushTokenController.findOne() +routes.post('/notifications/send/', + isAdministratorUser, + SchemaValidator(pushSendType, true), + pushTokenController.sendNotification() ); -routes.post('/me/pushtoken', +routes.post('/notifications/register', isLoggedUser, SchemaValidator(pushInputType, true), - pushTokenController.createOrUpdate() + pushTokenController.registerUser() ); module.exports = routes; \ No newline at end of file diff --git a/modules/push/push.service.js b/modules/push/push.service.js index 51178e2..e13abff 100644 --- a/modules/push/push.service.js +++ b/modules/push/push.service.js @@ -1,10 +1,109 @@ const _ = require('lodash'); +const Expo = require('expo-server-sdk'); const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper'); const models = require('../../core/models'); const cdnHelper = require('../../helpers/cdn.helper'); const { extractProviderInfo } = require('../../helpers/providers.helper'); -const extraMethods = {}; +const extraMethods = { + + + isValidPushToken: (token) => { + return Expo.isExpoPushToken(token); + }, + + getPushToken: (params) => { + return models.UserDevice.findOne({ + where: params, + }); + }, + + sendNotification: (message) => { + if (!extraMethods.isValidPushToken(message.to)) { + throw new Error(`Push token ${message.to} is not a valid Expo push token`); + } + + // The Expo push notification service accepts batches of notifications so + // that you don't need to send 1000 requests to send 1000 notifications. We + // recommend you batch your notifications to reduce the number of requests + // and to compress them (notifications with similar content will get + // compressed). + let chunks = expo.chunkPushNotifications(message); + let tickets = []; + (async () => { + // Send the chunks to the Expo push notification service. There are + // different strategies you could use. A simple one is to send one chunk at a + // time, which nicely spreads the load out over time: + 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/versions/latest/guides/push-notifications#response-format + } catch (error) { + console.error(error); + } + } + })(); + + // Later, after the Expo push notification service has delivered the + // notifications to Apple or Google (usually quickly, but allow the the service + // up to 30 minutes when under load), a "receipt" for each notification is + // created. The receipts will be available for at least a day; stale receipts + // are deleted. + // + // The ID of each receipt is sent back in the response "ticket" for each + // notification. In summary, sending a notification produces a ticket, which + // contains a receipt ID you later use to get the receipt. + // + // The receipts may contain error codes to which you must respond. In + // particular, Apple or Google may block apps that continue to send + // notifications to devices that have blocked notifications or have uninstalled + // your app. Expo does not control this policy and sends back the feedback from + // Apple and Google so you can handle it appropriately. + 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 () => { + // Like sending notifications, there are different strategies you could use + // to retrieve batches of receipts from the Expo service. + 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 receipt of receipts) { + if (receipt.status === 'ok') { + continue; + } else if (receipt.status === 'error') { + console.error(`There was an error sending a notification: ${receipt.message}`); + if (receipt.details && receipt.details.error) { + // The error codes are listed in the Expo documentation: + // https://docs.expo.io/versions/latest/guides/push-notifications#response-format + // You must handle the errors appropriately. + console.error(`The error code is ${receipt.details.error}`); + } + } + } + } catch (error) { + console.error(error); + } + } + })(); + } +}; module.exports = generateService(models.UserDevice, extraMethods); \ No newline at end of file diff --git a/modules/push/push.validations.js b/modules/push/push.validations.js index 49befa2..bfae5bc 100644 --- a/modules/push/push.validations.js +++ b/modules/push/push.validations.js @@ -4,6 +4,10 @@ const pushInputType = Joi.object().keys({ token: Joi.string().required(), }); +const pushSendType = Joi.object().keys({ + //token: Joi.string().required(), +}); + module.exports = { pushInputType, };