Skip to content

Commit 8a23c00

Browse files
marvelmflovilmart
authored andcommitted
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
1 parent a185c97 commit 8a23c00

File tree

4 files changed

+127
-17
lines changed

4 files changed

+127
-17
lines changed

spec/PushController.spec.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,4 +1254,84 @@ describe('PushController', () => {
12541254
.then(done, done.fail);
12551255
});
12561256
});
1257+
1258+
describe('With expiration defined', () => {
1259+
const auth = {isMaster: true};
1260+
const pushController = new PushController();
1261+
1262+
let config = Config.get(Parse.applicationId);
1263+
1264+
const pushes = [];
1265+
const pushAdapter = {
1266+
send(body, installations) {
1267+
pushes.push(body);
1268+
return successfulTransmissions(body, installations);
1269+
},
1270+
getValidPushTypes() {
1271+
return ["ios"];
1272+
}
1273+
};
1274+
1275+
beforeEach((done) => {
1276+
reconfigureServer({
1277+
push: {adapter: pushAdapter},
1278+
})
1279+
.then(() => {
1280+
config = Config.get(Parse.applicationId);
1281+
})
1282+
.then(done, done.fail);
1283+
});
1284+
1285+
it('should throw if both expiration_time and expiration_interval are set', () => {
1286+
expect(() => pushController.sendPush({
1287+
expiration_time: '2017-09-25T13:21:20.841Z',
1288+
expiration_interval: 1000,
1289+
}, {}, config, auth)).toThrow()
1290+
});
1291+
1292+
it('should throw on invalid expiration_interval', () => {
1293+
expect(() => pushController.sendPush({
1294+
expiration_interval: -1
1295+
}, {}, config, auth)).toThrow();
1296+
expect(() => pushController.sendPush({
1297+
expiration_interval: '',
1298+
}, {}, config, auth)).toThrow();
1299+
expect(() => pushController.sendPush({
1300+
expiration_time: {},
1301+
}, {}, config, auth)).toThrow();
1302+
});
1303+
1304+
describe('For immediate pushes',() => {
1305+
it('should transform the expiration_interval into an absolute time', (done) => {
1306+
const now = new Date('2017-09-25T13:30:10.452Z');
1307+
1308+
reconfigureServer({
1309+
push: {adapter: pushAdapter},
1310+
})
1311+
.then(() =>
1312+
new Promise((resolve) => {
1313+
pushController.sendPush({
1314+
data: {
1315+
alert: 'immediate push',
1316+
},
1317+
expiration_interval: 20 * 60, // twenty minutes
1318+
}, {}, Config.get(Parse.applicationId), auth, resolve, now)
1319+
}))
1320+
.then((pushStatusId) => {
1321+
const p = new Parse.Object('_PushStatus');
1322+
p.id = pushStatusId;
1323+
return p.fetch({useMasterKey: true});
1324+
})
1325+
.then((pushStatus) => {
1326+
expect(pushStatus.get('expiry')).toBeDefined('expiry must be set');
1327+
expect(pushStatus.get('expiry'))
1328+
.toEqual(new Date('2017-09-25T13:50:10.452Z').valueOf());
1329+
1330+
expect(pushStatus.get('expiration_interval')).toBeDefined('expiration_interval must be defined');
1331+
expect(pushStatus.get('expiration_interval')).toBe(20 * 60);
1332+
})
1333+
.then(done, done.fail);
1334+
});
1335+
});
1336+
});
12571337
});

src/Controllers/PushController.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,27 @@ import { applyDeviceTokenExists } from '../Push/utils';
77

88
export class PushController {
99

10-
sendPush(body = {}, where = {}, config, auth, onPushStatusSaved = () => {}) {
10+
sendPush(body = {}, where = {}, config, auth, onPushStatusSaved = () => {}, now = new Date()) {
1111
if (!config.hasPushSupport) {
1212
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
1313
'Missing push configuration');
1414
}
15+
1516
// Replace the expiration_time and push_time with a valid Unix epoch milliseconds time
1617
body.expiration_time = PushController.getExpirationTime(body);
18+
body.expiration_interval = PushController.getExpirationInterval(body);
19+
if (body.expiration_time && body.expiration_interval) {
20+
throw new Parse.Error(
21+
Parse.Error.PUSH_MISCONFIGURED,
22+
'Both expiration_time and expiration_interval cannot be set');
23+
}
24+
25+
// Immediate push
26+
if (body.expiration_interval && !body.hasOwnProperty('push_time')) {
27+
const ttlMs = body.expiration_interval * 1000;
28+
body.expiration_time = (new Date(now.valueOf() + ttlMs)).valueOf();
29+
}
30+
1731
const pushTime = PushController.getPushTime(body);
1832
if (pushTime && pushTime.date !== 'undefined') {
1933
body['push_time'] = PushController.formatPushTime(pushTime);
@@ -108,6 +122,20 @@ export class PushController {
108122
return expirationTime.valueOf();
109123
}
110124

125+
static getExpirationInterval(body = {}) {
126+
const hasExpirationInterval = body.hasOwnProperty('expiration_interval');
127+
if (!hasExpirationInterval) {
128+
return;
129+
}
130+
131+
var expirationIntervalParam = body['expiration_interval'];
132+
if (typeof expirationIntervalParam !== 'number' || expirationIntervalParam <= 0) {
133+
throw new Parse.Error(Parse.Error.PUSH_MISCONFIGURED,
134+
`expiration_interval must be a number greater than 0`);
135+
}
136+
return expirationIntervalParam;
137+
}
138+
111139
/**
112140
* Get push time from the request body.
113141
* @param {Object} request A request object

src/Controllers/SchemaController.js

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,22 +72,23 @@ const defaultColumns = Object.freeze({
7272
"subtitle": {type:'String'},
7373
},
7474
_PushStatus: {
75-
"pushTime": {type:'String'},
76-
"source": {type:'String'}, // rest or webui
77-
"query": {type:'String'}, // the stringified JSON query
78-
"payload": {type:'String'}, // the stringified JSON payload,
79-
"title": {type:'String'},
80-
"expiry": {type:'Number'},
81-
"status": {type:'String'},
82-
"numSent": {type:'Number'},
83-
"numFailed": {type:'Number'},
84-
"pushHash": {type:'String'},
85-
"errorMessage": {type:'Object'},
86-
"sentPerType": {type:'Object'},
87-
"failedPerType": {type:'Object'},
88-
"sentPerUTCOffset": {type:'Object'},
89-
"failedPerUTCOffset": {type:'Object'},
90-
"count": {type:'Number'}
75+
"pushTime": {type:'String'},
76+
"source": {type:'String'}, // rest or webui
77+
"query": {type:'String'}, // the stringified JSON query
78+
"payload": {type:'String'}, // the stringified JSON payload,
79+
"title": {type:'String'},
80+
"expiry": {type:'Number'},
81+
"expiration_interval": {type:'Number'},
82+
"status": {type:'String'},
83+
"numSent": {type:'Number'},
84+
"numFailed": {type:'Number'},
85+
"pushHash": {type:'String'},
86+
"errorMessage": {type:'Object'},
87+
"sentPerType": {type:'Object'},
88+
"failedPerType": {type:'Object'},
89+
"sentPerUTCOffset": {type:'Object'},
90+
"failedPerUTCOffset": {type:'Object'},
91+
"count": {type:'Number'}
9192
},
9293
_JobStatus: {
9394
"jobName": {type: 'String'},

src/StatusHandler.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ export function pushStatusHandler(config, existingObjectId) {
174174
source: options.source,
175175
title: options.title,
176176
expiry: body.expiration_time,
177+
expiration_interval: body.expiration_interval,
177178
status: status,
178179
numSent: 0,
179180
pushHash,

0 commit comments

Comments
 (0)