Adds support for PushScheduling (#3722)
* Add support for push scheduling Add a configuration flag on the server to handle the availability of push scheduling. * Update push controller to skip sending only if scheduling is configured Only skip push sending if scheduling is configured * Update bad conventions * Add CLI definitions for push scheduling * Adds tests for pushTime * Adds test for scheduling * nits * Test for not scheduled
This commit is contained in:
@@ -61,6 +61,7 @@ export class Config {
|
||||
this.pushControllerQueue = cacheInfo.pushControllerQueue;
|
||||
this.pushWorker = cacheInfo.pushWorker;
|
||||
this.hasPushSupport = cacheInfo.hasPushSupport;
|
||||
this.hasPushScheduledSupport = cacheInfo.hasPushScheduledSupport;
|
||||
this.loggerController = cacheInfo.loggerController;
|
||||
this.userController = cacheInfo.userController;
|
||||
this.authDataManager = cacheInfo.authDataManager;
|
||||
|
||||
@@ -12,8 +12,9 @@ export class PushController {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
'Missing push configuration');
|
||||
}
|
||||
// Replace the expiration_time with a valid Unix epoch milliseconds time
|
||||
body['expiration_time'] = PushController.getExpirationTime(body);
|
||||
// Replace the expiration_time and push_time with a valid Unix epoch milliseconds time
|
||||
body.expiration_time = PushController.getExpirationTime(body);
|
||||
body.push_time = PushController.getPushTime(body);
|
||||
// TODO: If the req can pass the checking, we return immediately instead of waiting
|
||||
// pushes to be sent. We probably change this behaviour in the future.
|
||||
let badgeUpdate = () => {
|
||||
@@ -49,6 +50,9 @@ export class PushController {
|
||||
onPushStatusSaved(pushStatus.objectId);
|
||||
return badgeUpdate();
|
||||
}).then(() => {
|
||||
if (body.push_time && config.hasPushScheduledSupport) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return config.pushControllerQueue.enqueue(body, where, config, auth, pushStatus);
|
||||
}).catch((err) => {
|
||||
return pushStatus.fail(err).then(() => {
|
||||
@@ -63,7 +67,7 @@ export class PushController {
|
||||
* @returns {Number|undefined} The expiration time if it exists in the request
|
||||
*/
|
||||
static getExpirationTime(body = {}) {
|
||||
var hasExpirationTime = !!body['expiration_time'];
|
||||
var hasExpirationTime = body.hasOwnProperty('expiration_time');
|
||||
if (!hasExpirationTime) {
|
||||
return;
|
||||
}
|
||||
@@ -84,6 +88,34 @@ export class PushController {
|
||||
}
|
||||
return expirationTime.valueOf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get push time from the request body.
|
||||
* @param {Object} request A request object
|
||||
* @returns {Number|undefined} The push time if it exists in the request
|
||||
*/
|
||||
static getPushTime(body = {}) {
|
||||
var hasPushTime = body.hasOwnProperty('push_time');
|
||||
if (!hasPushTime) {
|
||||
return;
|
||||
}
|
||||
var pushTimeParam = body['push_time'];
|
||||
var pushTime;
|
||||
if (typeof pushTimeParam === 'number') {
|
||||
pushTime = new Date(pushTimeParam * 1000);
|
||||
} else if (typeof pushTimeParam === 'string') {
|
||||
pushTime = new Date(pushTimeParam);
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
body['push_time'] + ' is not valid time.');
|
||||
}
|
||||
// Check pushTime is valid or not, if it is not valid, pushTime is NaN
|
||||
if (!isFinite(pushTime)) {
|
||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||
body['push_time'] + ' is not valid time.');
|
||||
}
|
||||
return pushTime;
|
||||
}
|
||||
}
|
||||
|
||||
export default PushController;
|
||||
|
||||
@@ -95,6 +95,7 @@ class ParseServer {
|
||||
analyticsAdapter,
|
||||
filesAdapter,
|
||||
push,
|
||||
scheduledPush = false,
|
||||
loggerAdapter,
|
||||
jsonLogs = defaults.jsonLogs,
|
||||
logsFolder = defaults.logsFolder,
|
||||
@@ -182,6 +183,7 @@ class ParseServer {
|
||||
const pushController = new PushController();
|
||||
|
||||
const hasPushSupport = pushAdapter && push;
|
||||
const hasPushScheduledSupport = pushAdapter && push && scheduledPush;
|
||||
|
||||
const {
|
||||
disablePushWorker
|
||||
@@ -259,7 +261,8 @@ class ParseServer {
|
||||
userSensitiveFields,
|
||||
pushWorker,
|
||||
pushControllerQueue,
|
||||
hasPushSupport
|
||||
hasPushSupport,
|
||||
hasPushScheduledSupport
|
||||
});
|
||||
|
||||
Config.validate(AppCache.get(appId));
|
||||
|
||||
@@ -30,7 +30,7 @@ export class FeaturesRouter extends PromiseRouter {
|
||||
},
|
||||
push: {
|
||||
immediatePush: req.config.hasPushSupport,
|
||||
scheduledPush: false,
|
||||
scheduledPush: req.config.hasPushScheduledSupport,
|
||||
storedPushData: req.config.hasPushSupport,
|
||||
pushAudiences: false,
|
||||
},
|
||||
|
||||
@@ -110,6 +110,18 @@ export function pushStatusHandler(config, objectId = newObjectId()) {
|
||||
const handler = statusHandler(PUSH_STATUS_COLLECTION, database);
|
||||
const setInitial = function(body = {}, where, options = {source: 'rest'}) {
|
||||
const now = new Date();
|
||||
let pushTime = new Date();
|
||||
let status = 'pending';
|
||||
if (body.hasOwnProperty('push_time')) {
|
||||
if (config.hasPushScheduledSupport) {
|
||||
pushTime = body.push_time;
|
||||
status = 'scheduled';
|
||||
} else {
|
||||
logger.warn('Trying to schedule a push while server is not configured.');
|
||||
logger.warn('Push will be sent immediately');
|
||||
}
|
||||
}
|
||||
|
||||
const data = body.data || {};
|
||||
const payloadString = JSON.stringify(data);
|
||||
let pushHash;
|
||||
@@ -123,13 +135,13 @@ export function pushStatusHandler(config, objectId = newObjectId()) {
|
||||
const object = {
|
||||
objectId,
|
||||
createdAt: now,
|
||||
pushTime: now.toISOString(),
|
||||
pushTime: pushTime.toISOString(),
|
||||
query: JSON.stringify(where),
|
||||
payload: payloadString,
|
||||
source: options.source,
|
||||
title: options.title,
|
||||
expiry: body.expiration_time,
|
||||
status: "pending",
|
||||
status: status,
|
||||
numSent: 0,
|
||||
pushHash,
|
||||
// lockdown!
|
||||
|
||||
@@ -81,6 +81,11 @@ export default {
|
||||
help: "Configuration for push, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Push",
|
||||
action: objectParser
|
||||
},
|
||||
"scheduledPush": {
|
||||
env: "PARSE_SERVER_SCHEDULED_PUSH",
|
||||
help: "Configuration for push scheduling. Defaults to false.",
|
||||
action: booleanParser
|
||||
},
|
||||
"oauth": {
|
||||
env: "PARSE_SERVER_OAUTH_PROVIDERS",
|
||||
help: "[DEPRECATED (use auth option)] Configuration for your oAuth providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
|
||||
|
||||
Reference in New Issue
Block a user