Skip to content

Commit 4d401d9

Browse files
committed
Stores the _PushStatus when sending push, set pending, and running states
1 parent 308fe14 commit 4d401d9

File tree

5 files changed

+104
-28
lines changed

5 files changed

+104
-28
lines changed

spec/PushController.spec.js

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ describe('PushController', () => {
105105
}).toThrow();
106106
done();
107107
});
108-
108+
109109
it('properly increment badges', (done) => {
110-
110+
111111
var payload = {data:{
112112
alert: "Hello World!",
113113
badge: "Increment",
@@ -122,15 +122,15 @@ describe('PushController', () => {
122122
installation.set("deviceType", "ios");
123123
installations.push(installation);
124124
}
125-
125+
126126
while(installations.length != 15) {
127127
var installation = new Parse.Object("_Installation");
128128
installation.set("installationId", "installation_"+installations.length);
129129
installation.set("deviceToken","device_token_"+installations.length)
130130
installation.set("deviceType", "android");
131131
installations.push(installation);
132132
}
133-
133+
134134
var pushAdapter = {
135135
send: function(body, installations) {
136136
var badge = body.data.badge;
@@ -151,14 +151,14 @@ describe('PushController', () => {
151151
return ["ios", "android"];
152152
}
153153
}
154-
154+
155155
var config = new Config(Parse.applicationId);
156156
var auth = {
157157
isMaster: true
158158
}
159-
159+
160160
var pushController = new PushController(pushAdapter, Parse.applicationId);
161-
Parse.Object.saveAll(installations).then((installations) => {
161+
Parse.Object.saveAll(installations).then((installations) => {
162162
return pushController.sendPush(payload, {}, config, auth);
163163
}).then((result) => {
164164
done();
@@ -167,11 +167,11 @@ describe('PushController', () => {
167167
fail("should not fail");
168168
done();
169169
});
170-
170+
171171
});
172-
172+
173173
it('properly set badges to 1', (done) => {
174-
174+
175175
var payload = {data: {
176176
alert: "Hello World!",
177177
badge: 1,
@@ -186,7 +186,7 @@ describe('PushController', () => {
186186
installation.set("deviceType", "ios");
187187
installations.push(installation);
188188
}
189-
189+
190190
var pushAdapter = {
191191
send: function(body, installations) {
192192
var badge = body.data.badge;
@@ -203,14 +203,14 @@ describe('PushController', () => {
203203
return ["ios"];
204204
}
205205
}
206-
206+
207207
var config = new Config(Parse.applicationId);
208208
var auth = {
209209
isMaster: true
210210
}
211-
211+
212212
var pushController = new PushController(pushAdapter, Parse.applicationId);
213-
Parse.Object.saveAll(installations).then((installations) => {
213+
Parse.Object.saveAll(installations).then((installations) => {
214214
return pushController.sendPush(payload, {}, config, auth);
215215
}).then((result) => {
216216
done();
@@ -219,15 +219,56 @@ describe('PushController', () => {
219219
fail("should not fail");
220220
done();
221221
});
222-
222+
223223
});
224-
224+
225+
it('properly creates _PushStatus', (done) => {
226+
227+
var payload = {data: {
228+
alert: "Hello World!",
229+
badge: 1,
230+
}}
231+
232+
var pushAdapter = {
233+
send: function(body, installations) {
234+
var badge = body.data.badge;
235+
return Promise.resolve({
236+
body: body,
237+
installations: installations
238+
})
239+
},
240+
getValidPushTypes: function() {
241+
return ["ios"];
242+
}
243+
}
244+
245+
var config = new Config(Parse.applicationId);
246+
var auth = {
247+
isMaster: true
248+
}
249+
250+
var pushController = new PushController(pushAdapter, Parse.applicationId);
251+
pushController.sendPush(payload, {}, config, auth).then((result) => {
252+
let query = new Parse.Query('_PushStatus');
253+
return query.find({useMasterKey: true});
254+
}).then((results) => {
255+
expect(results.length).toBe(1);
256+
let result = results[0];
257+
expect(result.get('source')).toEqual('rest');
258+
expect(result.get('query')).toEqual(JSON.stringify({}));
259+
expect(result.get('payload')).toEqual(payload.data);
260+
expect(result.get('status')).toEqual("running");
261+
done();
262+
});
263+
264+
});
265+
225266
it('should support full RESTQuery for increment', (done) => {
226267
var payload = {data: {
227268
alert: "Hello World!",
228269
badge: 'Increment',
229270
}}
230-
271+
231272
var pushAdapter = {
232273
send: function(body, installations) {
233274
return Promise.resolve();
@@ -236,12 +277,12 @@ describe('PushController', () => {
236277
return ["ios"];
237278
}
238279
}
239-
280+
240281
var config = new Config(Parse.applicationId);
241282
var auth = {
242283
isMaster: true
243284
}
244-
285+
245286
let where = {
246287
'deviceToken': {
247288
'$inQuery': {

src/Adapters/Push/PushAdapter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
//
55
// Adapter classes must implement the following functions:
66
// * getValidPushTypes()
7-
// * send(devices, installations)
7+
// * send(devices, installations, pushStatus)
88
//
99
// Default is ParsePushAdapter, which uses GCM for
1010
// android push and APNS for ios push.
1111

1212
export class PushAdapter {
13-
send(devices, installations) { }
13+
send(devices, installations, pushStatus) { }
1414

1515
/**
1616
* Get an array of valid push types.

src/Controllers/PushController.js

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import rest from '../rest';
44
import AdaptableController from './AdaptableController';
55
import { PushAdapter } from '../Adapters/Push/PushAdapter';
66
import deepcopy from 'deepcopy';
7+
import { md5Hash } from '../cryptoUtils';
78
import features from '../features';
89
import RestQuery from '../RestQuery';
10+
import RestWrite from '../RestWrite';
911

1012
const FEATURE_NAME = 'push';
1113
const UNSUPPORTED_BADGE_KEY = "unsupported";
@@ -65,7 +67,7 @@ export class PushController extends AdaptableController {
6567
}
6668
let updateWhere = deepcopy(where);
6769

68-
badgeUpdate = () => {
70+
badgeUpdate = () => {
6971
let badgeQuery = new RestQuery(config, auth, '_Installation', updateWhere);
7072
return badgeQuery.buildRestWhere().then(() => {
7173
let restWhere = deepcopy(badgeQuery.restWhere);
@@ -81,8 +83,13 @@ export class PushController extends AdaptableController {
8183
})
8284
}
8385
}
84-
85-
return badgeUpdate().then(() => {
86+
let pushStatus;
87+
return Promise.resolve().then(() => {
88+
return this.saveInitialPushStatus(body, where, config);
89+
}).then((res) => {
90+
pushStatus = res.response;
91+
return badgeUpdate();
92+
}).then(() => {
8693
return rest.find(config, auth, '_Installation', where);
8794
}).then((response) => {
8895
if (body.data && body.data.badge && body.data.badge == "Increment") {
@@ -105,14 +112,38 @@ export class PushController extends AdaptableController {
105112
} else {
106113
payload.data.badge = parseInt(badge);
107114
}
108-
return pushAdapter.send(payload, badgeInstallationsMap[badge]);
115+
return pushAdapter.send(payload, badgeInstallationsMap[badge], pushStatus);
109116
});
110117
return Promise.all(promises);
111118
}
112-
return pushAdapter.send(body, response.results);
119+
return pushAdapter.send(body, response.results, pushStatus);
120+
}).then(() => {
121+
return this.updatePushStatus({status: "running"}, pushStatus, config);
113122
});
114123
}
115124

125+
saveInitialPushStatus(body, where, config, options = {source: 'rest'}) {
126+
let pushStatus = {
127+
pushTime: (new Date()).toISOString(),
128+
query: JSON.stringify(where),
129+
payload: body.data,
130+
source: options.source,
131+
title: options.title,
132+
expiry: body.expiration_time,
133+
status: "pending",
134+
numSent: 0,
135+
pushHash: md5Hash(JSON.stringify(body.data)),
136+
ACL: new Parse.ACL() // lockdown!
137+
}
138+
let restWrite = new RestWrite(config, {isMaster: true},'_PushStatus',null, pushStatus);
139+
return restWrite.execute();
140+
}
141+
142+
updatePushStatus(update, pushStatus, config) {
143+
let restWrite = new RestWrite(config, {isMaster: true}, '_PushStatus', {objectId: pushStatus.objectId, "status": "pending"}, update);
144+
return restWrite.execute();
145+
}
146+
116147
/**
117148
* Get expiration time from the request body.
118149
* @param {Object} request A request object

src/Schema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ var defaultColumns = {
7171
},
7272
_PushStatus: {
7373
"pushTime": {type:'String'},
74-
"source": {type:'String'}, // rest or web
74+
"source": {type:'String'}, // rest or webui
7575
"query": {type:'String'}, // the stringified JSON query
7676
"payload": {type:'Object'}, // the JSON payload,
7777
"title": {type:'String'},

src/cryptoUtils.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* @flow */
22

3-
import { randomBytes } from 'crypto';
3+
import { randomBytes, createHash } from 'crypto';
44

55
// Returns a new random hex string of the given even size.
66
export function randomHexString(size: number): string {
@@ -44,3 +44,7 @@ export function newObjectId(): string {
4444
export function newToken(): string {
4545
return randomHexString(32);
4646
}
47+
48+
export function md5Hash(string: string): string {
49+
return createHash('md5').update(string).digest('hex');
50+
}

0 commit comments

Comments
 (0)