Push
This commit is contained in:
parent
47b1f87a79
commit
7a3c1ce5b6
@ -38,37 +38,70 @@ const extraControllers = {
|
||||
}
|
||||
|
||||
try {
|
||||
let getUserDevicesPromise = (userId) => userDeviceService.fetchAll({ params: { userId: userId }}, context);
|
||||
let getUserDevicesPromise = (userId) => userDeviceService.fetchAll({ params: { userId: userId }}, context).then(function(result) {
|
||||
return new Promise(function(resolve) { resolve(result.rows) });
|
||||
});
|
||||
let saveNotificationPromise = (notification) => notificationService.create(notification, context);
|
||||
let sendNotificationsPromise = (messages) => notificationService.sendNotification(messages);
|
||||
let disableUserDevicePromise = (userDevice) => userDeviceService.update({
|
||||
userId: userDevice.userId,
|
||||
token: userDevice.token,
|
||||
}, { valid: false }, context);
|
||||
let disableUserDevicePromise = (token) => userDeviceService.update({ params: {
|
||||
token: token,
|
||||
}}, { valid: false }, context);
|
||||
|
||||
let disableInvalidUserDevicesPromise = (userDevices) => {
|
||||
return new Promise(function (resolve) {
|
||||
let _userDevices = [];
|
||||
userDevices.forEach(async function (userDevice) {
|
||||
if (!userDeviceService.isValidPushToken(userDevice.token)) {
|
||||
await disableUserDevicePromise(userDevice.token);
|
||||
} else {
|
||||
_userDevices.push(userDevice);
|
||||
}
|
||||
});
|
||||
|
||||
resolve(_userDevices)
|
||||
});
|
||||
};
|
||||
|
||||
let disableUserDevicesWithErrorStatus = (messages, tickets) => {
|
||||
return new Promise(function (resolve) {
|
||||
tickets.forEach(async function (ticket, index) {
|
||||
if ((ticket.status === 'error') && (ticket.details.error === 'DeviceNotRegistered')) {
|
||||
await disableUserDevicePromise(messages[index].to)
|
||||
}
|
||||
});
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
let saveResponseStatusPromise = (messages, tickets) => notificationDetailService.saveNotificationDetails(messages, tickets);
|
||||
|
||||
const notificationRecord = {
|
||||
title: req.body.title,
|
||||
body: req.body.message,
|
||||
ttl: req.body.ttl,
|
||||
priority: req.body.priority,
|
||||
data: req.body.data || req.body.userIds,
|
||||
ttl: req.body.ttl || undefined,
|
||||
priority: req.body.priority || 'default',
|
||||
data: req.body.data || { userIds: req.body.userIds },
|
||||
};
|
||||
|
||||
let buildMessagePromise = async (userDevices) => {
|
||||
let message = undefined;
|
||||
userDevices.rows.forEach(async function (userDevice) {
|
||||
if (notificationService.isValidPushToken(userDevice.token)) {
|
||||
message = {
|
||||
...notificationRecord,
|
||||
let buildMessagesPromise = (userDevices) => {
|
||||
return new Promise(function (resolve) {
|
||||
let messages = [];
|
||||
|
||||
userDevices.forEach(async function (userDevice) {
|
||||
messages.push({
|
||||
title: notificationRecord.title,
|
||||
body: notificationRecord.body,
|
||||
ttl: notificationRecord.ttl,
|
||||
priority: notificationRecord.priority,
|
||||
userId: userDevice.userId,
|
||||
to: userDevice.token,
|
||||
sound: 'default',
|
||||
};
|
||||
} else {
|
||||
await disableUserDevicePromise(userDevice);
|
||||
}
|
||||
notificationId: notificationRecord.id,
|
||||
});
|
||||
});
|
||||
|
||||
resolve(messages)
|
||||
});
|
||||
return new Promise(function(resolve) { resolve(message) });
|
||||
};
|
||||
|
||||
let getUserDevicesList = [];
|
||||
@ -77,15 +110,27 @@ const extraControllers = {
|
||||
getUserDevicesList.push(getUserDevicesPromise(userId));
|
||||
});
|
||||
|
||||
receipt = await saveNotificationPromise(notificationRecord)
|
||||
.then(function() {
|
||||
saveNotificationPromise(notificationRecord)
|
||||
.then(function(notification) {
|
||||
notificationRecord.id = notification.id;
|
||||
return Promise.all(getUserDevicesList)
|
||||
}).then(function(userDeviceList) {
|
||||
return Promise.all(userDeviceList.map(buildMessagePromise))
|
||||
}).then(sendNotificationsPromise)
|
||||
|
||||
}).then(function (userDeviceList) {
|
||||
return new Promise(function(resolve) { resolve(userDeviceList[0]); });
|
||||
})
|
||||
.then(disableInvalidUserDevicesPromise)
|
||||
.then(buildMessagesPromise)
|
||||
.then(sendNotificationsPromise)
|
||||
.then(function({ messages, tickets }) {
|
||||
let _saveStatus = saveResponseStatusPromise(messages, tickets);
|
||||
let _disableDevices = disableUserDevicesWithErrorStatus(messages, tickets);
|
||||
|
||||
return Promise.all([_saveStatus, _disableDevices]);
|
||||
})
|
||||
.then(function (details) {
|
||||
console.log(details);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return handleErrorResponse(controllerOptions.MODULE_NAME, 'sendNotification', error, res)
|
||||
} finally {
|
||||
return handleResultResponse(receipt, null, null, res, httpStatus.OK);
|
||||
|
||||
@ -8,10 +8,6 @@ const expo = new Expo();
|
||||
|
||||
const extraMethods = {
|
||||
|
||||
isValidPushToken: (token) => {
|
||||
return Expo.isExpoPushToken(token);
|
||||
},
|
||||
|
||||
sendNotification: async (messages) => {
|
||||
|
||||
// The Expo push notification service accepts batches of notifications so
|
||||
@ -43,33 +39,10 @@ const extraMethods = {
|
||||
// Apple and Google so you can handle it appropriately.
|
||||
|
||||
let chunks = expo.chunkPushNotifications(messages);
|
||||
let tickets = await _sendPushNotificationsAsync(chunks);
|
||||
|
||||
console.log(tickets);
|
||||
let receiptIds = [];
|
||||
let invalidTokens = [];
|
||||
for (let [key, ticket] of tickets.entries()) {
|
||||
// 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);
|
||||
} else {
|
||||
if ((ticket.status === 'error') && (ticket.details.error === 'DeviceNotRegistered')) {
|
||||
invalidTokens.push({
|
||||
...messages[key],
|
||||
valid: false,
|
||||
invalidated: moment(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(receiptIds);
|
||||
console.log(invalidTokens);
|
||||
|
||||
let notifications = await _saveNotifications(messages, tickets);
|
||||
return new Promise(function (resolve) { resolve(notifications) });
|
||||
|
||||
return {
|
||||
messages,
|
||||
tickets: await _sendPushNotificationsAsync(chunks)
|
||||
};
|
||||
},
|
||||
|
||||
getNotificationsWithoutReceipt: async() => {
|
||||
@ -88,76 +61,66 @@ module.exports = generateService(models.Notification, extraMethods);
|
||||
|
||||
|
||||
const _sendPushNotificationsAsync = async function (chunks) {
|
||||
let tickets = [];
|
||||
// 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);
|
||||
tickets.push(...ticketChunk);
|
||||
return new Promise(async function (resolve) {
|
||||
let tickets = [];
|
||||
// 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);
|
||||
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
|
||||
// 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);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(function (resolve) { resolve(tickets) });
|
||||
resolve(tickets);
|
||||
});
|
||||
};
|
||||
|
||||
const _getPushNotificationsResultAsync = async function (receiptIdChunks) {
|
||||
// Like sending notifications, there are different strategies you could use
|
||||
// to retrieve batches of receipts from the Expo service.
|
||||
return new Promise(async function (resolve) {
|
||||
// Like sending notifications, there are different strategies you could use
|
||||
// to retrieve batches of receipts from the Expo service.
|
||||
|
||||
let result = [];
|
||||
let result = [];
|
||||
|
||||
console.log(receiptIdChunks);
|
||||
console.log(receiptIdChunks);
|
||||
|
||||
for (let chunk of receiptIdChunks) {
|
||||
try {
|
||||
let receipts = await expo.getPushNotificationReceiptsAsync(chunk);
|
||||
console.log('hola', receipts);
|
||||
for (let chunk of receiptIdChunks) {
|
||||
try {
|
||||
let receipts = await expo.getPushNotificationReceiptsAsync(chunk);
|
||||
console.log('hola', receipts);
|
||||
|
||||
// The receipts specify whether Apple or Google successfully received the
|
||||
// notification and information about an error, if one occurred.
|
||||
for (let key in receipts) {
|
||||
if (receipts[key].status === 'ok') {
|
||||
result.push[receipts[key]];
|
||||
continue;
|
||||
} else if (receipts[key].status === 'error') {
|
||||
console.error(`There was an error sending a notification: ${receipts[key].message}`);
|
||||
if (receipts[key].details && receipts[key].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 ${receipts[key].details.error}`);
|
||||
// The receipts specify whether Apple or Google successfully received the
|
||||
// notification and information about an error, if one occurred.
|
||||
for (let key in receipts) {
|
||||
if (receipts[key].status === 'ok') {
|
||||
result.push[receipts[key]];
|
||||
continue;
|
||||
} else if (receipts[key].status === 'error') {
|
||||
console.error(`There was an error sending a notification: ${receipts[key].message}`);
|
||||
if (receipts[key].details && receipts[key].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 ${receipts[key].details.error}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(function (resolve) { resolve(result) });
|
||||
resolve(result);
|
||||
});
|
||||
}
|
||||
|
||||
const _saveNotifications = async function (messages, tickets) {
|
||||
let notifications = [];
|
||||
messages.forEach(function (message, index) {
|
||||
let notification = models.NotificationDetail.build({
|
||||
...message,
|
||||
ticket: tickets[index].id,
|
||||
status: tickets[index].status,
|
||||
error: (tickets[index].status === 'error') ? tickets[index].details.error : undefined,
|
||||
});
|
||||
notifications.push(notification);
|
||||
});
|
||||
|
||||
return new Promise(function (resolve) { resolve(notifications) });
|
||||
}
|
||||
@ -32,7 +32,7 @@ module.exports = function (sequelize, DataTypes) {
|
||||
},
|
||||
ticket: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
allowNull: true,
|
||||
},
|
||||
deliveryDate: {
|
||||
type: DataTypes.DATE,
|
||||
|
||||
@ -4,6 +4,23 @@ const { generateService, parseParamsToFindOptions } = require('../../helpers/ser
|
||||
const models = require('../../core/models');
|
||||
|
||||
const extraMethods = {
|
||||
saveNotificationDetails: async function (messages, tickets) {
|
||||
return new Promise(function (resolve) {
|
||||
messages.forEach(async function (message, index) {
|
||||
let notification = models.NotificationDetail.build({
|
||||
...message,
|
||||
token: message.to,
|
||||
ticket: tickets[index].id ? tickets[index].id : undefined,
|
||||
deliveryDate: moment(),
|
||||
deliveryStatus: (tickets[index].status === 'error') ? tickets[index].details.error : tickets[index].status,
|
||||
notificationId: message.notificationId,
|
||||
});
|
||||
await notification.save();
|
||||
});
|
||||
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -3,10 +3,25 @@ const { Expo } = require('expo-server-sdk');
|
||||
const { generateService, parseParamsToFindOptions } = require('../../helpers/service.helper');
|
||||
const models = require('../../core/models');
|
||||
|
||||
// Create a new Expo SDK client
|
||||
const expo = new Expo();
|
||||
|
||||
const extraMethods = {
|
||||
isValidPushToken: (token) => {
|
||||
return Expo.isExpoPushToken(token);
|
||||
},
|
||||
|
||||
afterFetchAll: (result, params, context) => {
|
||||
|
||||
if (!result.count) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let rows = result.rows.map(row => row.toJSON());
|
||||
|
||||
return {
|
||||
count: result.count,
|
||||
rows: rows
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
getPushToken: (params) => {
|
||||
return models.UserDevice.findOne({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user