Skip to content

Add support for push scheduling #3717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
36 changes: 34 additions & 2 deletions src/Controllers/PushController.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
// 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 = () => {
Expand Down Expand Up @@ -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(() => {
Expand All @@ -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;
}
Expand All @@ -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 = {}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we add a test for that piece?

There is a bit of logic there, even trivial but that would help not introduce any regression.

I could add them on the top of your branch if you don't have much time :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we've to add a test. Any help is appreciated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wish i knew enough to help.. i will check your test to help further in any future contribution. Tks in advance @flovilmart

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.valueOf();
}
}

export default PushController;
5 changes: 4 additions & 1 deletion src/ParseServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class ParseServer {
analyticsAdapter,
filesAdapter,
push,
scheduledPush = false,
loggerAdapter,
jsonLogs = defaults.jsonLogs,
logsFolder = defaults.logsFolder,
Expand Down Expand Up @@ -182,6 +183,7 @@ class ParseServer {
const pushController = new PushController();

const hasPushSupport = pushAdapter && push;
const hasPushScheduledSupport = pushAdapter && push && scheduledPush;

const {
disablePushWorker
Expand Down Expand Up @@ -259,7 +261,8 @@ class ParseServer {
userSensitiveFields,
pushWorker,
pushControllerQueue,
hasPushSupport
hasPushSupport,
hasPushScheduledSupport
});

Config.validate(AppCache.get(appId));
Expand Down
2 changes: 1 addition & 1 deletion src/Routers/FeaturesRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down
6 changes: 4 additions & 2 deletions src/StatusHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ 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();
const pushTime = body.push_time || new Date();
const status = body.push_time ? "scheduled" : "pending";
const data = body.data || {};
const payloadString = JSON.stringify(data);
let pushHash;
Expand All @@ -123,13 +125,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!
Expand Down
5 changes: 5 additions & 0 deletions src/cli/definitions/parse-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down