Add support for expiration interval in Push (#4202)
* Add support for expiration_interval in Push * Support expiration_interval for immediate pushes * Test * Add 'expiration_interval' to _PushStatus class * Fix coverage
This commit is contained in:
@@ -1254,4 +1254,84 @@ describe('PushController', () => {
|
|||||||
.then(done, done.fail);
|
.then(done, done.fail);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('With expiration defined', () => {
|
||||||
|
const auth = {isMaster: true};
|
||||||
|
const pushController = new PushController();
|
||||||
|
|
||||||
|
let config = Config.get(Parse.applicationId);
|
||||||
|
|
||||||
|
const pushes = [];
|
||||||
|
const pushAdapter = {
|
||||||
|
send(body, installations) {
|
||||||
|
pushes.push(body);
|
||||||
|
return successfulTransmissions(body, installations);
|
||||||
|
},
|
||||||
|
getValidPushTypes() {
|
||||||
|
return ["ios"];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach((done) => {
|
||||||
|
reconfigureServer({
|
||||||
|
push: {adapter: pushAdapter},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
config = Config.get(Parse.applicationId);
|
||||||
|
})
|
||||||
|
.then(done, done.fail);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if both expiration_time and expiration_interval are set', () => {
|
||||||
|
expect(() => pushController.sendPush({
|
||||||
|
expiration_time: '2017-09-25T13:21:20.841Z',
|
||||||
|
expiration_interval: 1000,
|
||||||
|
}, {}, config, auth)).toThrow()
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw on invalid expiration_interval', () => {
|
||||||
|
expect(() => pushController.sendPush({
|
||||||
|
expiration_interval: -1
|
||||||
|
}, {}, config, auth)).toThrow();
|
||||||
|
expect(() => pushController.sendPush({
|
||||||
|
expiration_interval: '',
|
||||||
|
}, {}, config, auth)).toThrow();
|
||||||
|
expect(() => pushController.sendPush({
|
||||||
|
expiration_time: {},
|
||||||
|
}, {}, config, auth)).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('For immediate pushes',() => {
|
||||||
|
it('should transform the expiration_interval into an absolute time', (done) => {
|
||||||
|
const now = new Date('2017-09-25T13:30:10.452Z');
|
||||||
|
|
||||||
|
reconfigureServer({
|
||||||
|
push: {adapter: pushAdapter},
|
||||||
|
})
|
||||||
|
.then(() =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
pushController.sendPush({
|
||||||
|
data: {
|
||||||
|
alert: 'immediate push',
|
||||||
|
},
|
||||||
|
expiration_interval: 20 * 60, // twenty minutes
|
||||||
|
}, {}, Config.get(Parse.applicationId), auth, resolve, now)
|
||||||
|
}))
|
||||||
|
.then((pushStatusId) => {
|
||||||
|
const p = new Parse.Object('_PushStatus');
|
||||||
|
p.id = pushStatusId;
|
||||||
|
return p.fetch({useMasterKey: true});
|
||||||
|
})
|
||||||
|
.then((pushStatus) => {
|
||||||
|
expect(pushStatus.get('expiry')).toBeDefined('expiry must be set');
|
||||||
|
expect(pushStatus.get('expiry'))
|
||||||
|
.toEqual(new Date('2017-09-25T13:50:10.452Z').valueOf());
|
||||||
|
|
||||||
|
expect(pushStatus.get('expiration_interval')).toBeDefined('expiration_interval must be defined');
|
||||||
|
expect(pushStatus.get('expiration_interval')).toBe(20 * 60);
|
||||||
|
})
|
||||||
|
.then(done, done.fail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,13 +7,27 @@ import { applyDeviceTokenExists } from '../Push/utils';
|
|||||||
|
|
||||||
export class PushController {
|
export class PushController {
|
||||||
|
|
||||||
sendPush(body = {}, where = {}, config, auth, onPushStatusSaved = () => {}) {
|
sendPush(body = {}, where = {}, config, auth, onPushStatusSaved = () => {}, now = new Date()) {
|
||||||
if (!config.hasPushSupport) {
|
if (!config.hasPushSupport) {
|
||||||
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||||
'Missing push configuration');
|
'Missing push configuration');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace the expiration_time and push_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.expiration_time = PushController.getExpirationTime(body);
|
||||||
|
body.expiration_interval = PushController.getExpirationInterval(body);
|
||||||
|
if (body.expiration_time && body.expiration_interval) {
|
||||||
|
throw new Parse.Error(
|
||||||
|
Parse.Error.PUSH_MISCONFIGURED,
|
||||||
|
'Both expiration_time and expiration_interval cannot be set');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Immediate push
|
||||||
|
if (body.expiration_interval && !body.hasOwnProperty('push_time')) {
|
||||||
|
const ttlMs = body.expiration_interval * 1000;
|
||||||
|
body.expiration_time = (new Date(now.valueOf() + ttlMs)).valueOf();
|
||||||
|
}
|
||||||
|
|
||||||
const pushTime = PushController.getPushTime(body);
|
const pushTime = PushController.getPushTime(body);
|
||||||
if (pushTime && pushTime.date !== 'undefined') {
|
if (pushTime && pushTime.date !== 'undefined') {
|
||||||
body['push_time'] = PushController.formatPushTime(pushTime);
|
body['push_time'] = PushController.formatPushTime(pushTime);
|
||||||
@@ -108,6 +122,20 @@ export class PushController {
|
|||||||
return expirationTime.valueOf();
|
return expirationTime.valueOf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getExpirationInterval(body = {}) {
|
||||||
|
const hasExpirationInterval = body.hasOwnProperty('expiration_interval');
|
||||||
|
if (!hasExpirationInterval) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expirationIntervalParam = body['expiration_interval'];
|
||||||
|
if (typeof expirationIntervalParam !== 'number' || expirationIntervalParam <= 0) {
|
||||||
|
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
|
||||||
|
`expiration_interval must be a number greater than 0`);
|
||||||
|
}
|
||||||
|
return expirationIntervalParam;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get push time from the request body.
|
* Get push time from the request body.
|
||||||
* @param {Object} request A request object
|
* @param {Object} request A request object
|
||||||
|
|||||||
@@ -72,22 +72,23 @@ const defaultColumns = Object.freeze({
|
|||||||
"subtitle": {type:'String'},
|
"subtitle": {type:'String'},
|
||||||
},
|
},
|
||||||
_PushStatus: {
|
_PushStatus: {
|
||||||
"pushTime": {type:'String'},
|
"pushTime": {type:'String'},
|
||||||
"source": {type:'String'}, // rest or webui
|
"source": {type:'String'}, // rest or webui
|
||||||
"query": {type:'String'}, // the stringified JSON query
|
"query": {type:'String'}, // the stringified JSON query
|
||||||
"payload": {type:'String'}, // the stringified JSON payload,
|
"payload": {type:'String'}, // the stringified JSON payload,
|
||||||
"title": {type:'String'},
|
"title": {type:'String'},
|
||||||
"expiry": {type:'Number'},
|
"expiry": {type:'Number'},
|
||||||
"status": {type:'String'},
|
"expiration_interval": {type:'Number'},
|
||||||
"numSent": {type:'Number'},
|
"status": {type:'String'},
|
||||||
"numFailed": {type:'Number'},
|
"numSent": {type:'Number'},
|
||||||
"pushHash": {type:'String'},
|
"numFailed": {type:'Number'},
|
||||||
"errorMessage": {type:'Object'},
|
"pushHash": {type:'String'},
|
||||||
"sentPerType": {type:'Object'},
|
"errorMessage": {type:'Object'},
|
||||||
"failedPerType": {type:'Object'},
|
"sentPerType": {type:'Object'},
|
||||||
"sentPerUTCOffset": {type:'Object'},
|
"failedPerType": {type:'Object'},
|
||||||
"failedPerUTCOffset": {type:'Object'},
|
"sentPerUTCOffset": {type:'Object'},
|
||||||
"count": {type:'Number'}
|
"failedPerUTCOffset": {type:'Object'},
|
||||||
|
"count": {type:'Number'}
|
||||||
},
|
},
|
||||||
_JobStatus: {
|
_JobStatus: {
|
||||||
"jobName": {type: 'String'},
|
"jobName": {type: 'String'},
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ export function pushStatusHandler(config, existingObjectId) {
|
|||||||
source: options.source,
|
source: options.source,
|
||||||
title: options.title,
|
title: options.title,
|
||||||
expiry: body.expiration_time,
|
expiry: body.expiration_time,
|
||||||
|
expiration_interval: body.expiration_interval,
|
||||||
status: status,
|
status: status,
|
||||||
numSent: 0,
|
numSent: 0,
|
||||||
pushHash,
|
pushHash,
|
||||||
|
|||||||
Reference in New Issue
Block a user