From 6cee57cf491ac6eb5dc421b49aee555596e1ebe2 Mon Sep 17 00:00:00 2001 From: Alex Black Date: Sun, 23 Oct 2016 18:15:20 -0700 Subject: [PATCH 01/10] stub --- src/Controllers/PushController.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Controllers/PushController.js b/src/Controllers/PushController.js index 84e2a79d4b..810bd16209 100644 --- a/src/Controllers/PushController.js +++ b/src/Controllers/PushController.js @@ -93,6 +93,10 @@ export class PushController extends AdaptableController { if (!response.results) { return Promise.reject({error: 'PushController: no results in query'}) } + return response; + }).then((response) => { + return this.starTracking(response.results, pushStatus); + }).then((response) => { pushStatus.setRunning(response.results); return this.sendToAdapter(body, response.results, pushStatus, config); }).then((results) => { @@ -104,6 +108,16 @@ export class PushController extends AdaptableController { }); } + startTracking(installations, pushStatus) { + // todo: insert a Push object per installation, with timestamp, and pushStatus.objectId + return Promise.resolve(); + } + + updateTracking(installations, pushStatus, results) { + // todo, find and update each of the Push objects with their result + return Promise.resolve(); + } + sendToAdapter(body, installations, pushStatus, config) { if (body.data && body.data.badge && typeof body.data.badge == 'string' && body.data.badge.toLowerCase() == "increment") { // Collect the badges to reduce the # of calls From 2bf4bf62f225c0a64b2c5b6a3a9fec2c606c7d10 Mon Sep 17 00:00:00 2001 From: Alex Black Date: Sun, 23 Oct 2016 18:22:38 -0700 Subject: [PATCH 02/10] update --- src/Controllers/PushController.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Controllers/PushController.js b/src/Controllers/PushController.js index 810bd16209..5f99ad5754 100644 --- a/src/Controllers/PushController.js +++ b/src/Controllers/PushController.js @@ -100,7 +100,9 @@ export class PushController extends AdaptableController { pushStatus.setRunning(response.results); return this.sendToAdapter(body, response.results, pushStatus, config); }).then((results) => { - return pushStatus.complete(results); + return pushStatus.complete(results).then(() => { + return updateTracking(response.results, results, pushStatus); + }; }).catch((err) => { return pushStatus.fail(err).then(() => { throw err; From 71f3b8a9e769bad3959393cee97111b5c0465ecb Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 26 Oct 2016 22:38:34 -0700 Subject: [PATCH 03/10] early draft --- src/Controllers/PushController.js | 16 +-------- src/StatusHandler.js | 54 +++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/Controllers/PushController.js b/src/Controllers/PushController.js index 5f99ad5754..ea790573fd 100644 --- a/src/Controllers/PushController.js +++ b/src/Controllers/PushController.js @@ -94,15 +94,11 @@ export class PushController extends AdaptableController { return Promise.reject({error: 'PushController: no results in query'}) } return response; - }).then((response) => { - return this.starTracking(response.results, pushStatus); }).then((response) => { pushStatus.setRunning(response.results); return this.sendToAdapter(body, response.results, pushStatus, config); }).then((results) => { - return pushStatus.complete(results).then(() => { - return updateTracking(response.results, results, pushStatus); - }; + return pushStatus.complete(results); }).catch((err) => { return pushStatus.fail(err).then(() => { throw err; @@ -110,16 +106,6 @@ export class PushController extends AdaptableController { }); } - startTracking(installations, pushStatus) { - // todo: insert a Push object per installation, with timestamp, and pushStatus.objectId - return Promise.resolve(); - } - - updateTracking(installations, pushStatus, results) { - // todo, find and update each of the Push objects with their result - return Promise.resolve(); - } - sendToAdapter(body, installations, pushStatus, config) { if (body.data && body.data.badge && typeof body.data.badge == 'string' && body.data.badge.toLowerCase() == "increment") { // Collect the badges to reduce the # of calls diff --git a/src/StatusHandler.js b/src/StatusHandler.js index 8d7718dfc1..0e3a9fe1d6 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -1,8 +1,10 @@ import { md5Hash, newObjectId } from './cryptoUtils'; import { logger } from './logger'; +import _ from 'lodash'; const PUSH_STATUS_COLLECTION = '_PushStatus'; const JOB_STATUS_COLLECTION = '_JobStatus'; +const PUSH_COLLECTION = 'Push'; export function flatten(array) { return array.reduce((memo, element) => { @@ -34,9 +36,49 @@ function statusHandler(className, database) { return lastPromise; } + function createPush(object) { + lastPromise = lastPromise.then(() => { + return database.create(PUSH_COLLECTION, object).then(() => { + return Promise.resolve(object); + }); + }); + return lastPromise; + } + + function insertPushes(installations, pushStatusObjectId) { + // Insert a Push object for each installation we're pushing to + let promises = _.map(installations, installation => { + let now = new Date(); + let pushObjectId = newObjectId(); + let push = { + pushObjectId, + createdAt: now, + installation: { + __type: 'Pointer', + className: "_Installation", + objectId: installation.id, + }, + pushStatus: { + __type: 'Pointer', + className: className, + objectId: pushStatusObjectId, + } + }; + return createPush(push); + }); + return Promise.all(promises); + } + + function updatePushes(pushStatusObjectId, results) { + return Promise.resolve(); + } + return Object.freeze({ create, - update + update, + createPush, + insertPushes, + updatePushes }) } @@ -138,8 +180,10 @@ export function pushStatusHandler(config) { let setRunning = function(installations) { logger.verbose('sending push to %d installations', installations.length); - return handler.update({status:"pending", objectId: objectId}, + return handler.insertPushes(installations, objectId).then(() => { + return handler.update({status:"pending", objectId: objectId}, {status: "running", updatedAt: new Date() }); + }); } let complete = function(results) { @@ -173,7 +217,11 @@ export function pushStatusHandler(config) { }, update); } logger.verbose('sent push! %d success, %d failures', update.numSent, update.numFailed); - return handler.update({status:"running", objectId }, update); + return handler.update({status:"running", objectId }, update).then((result) => { + return handler.updatePushes(objectId, results).then(() => { + return result; + }); + }); } let fail = function(err) { From 4434fc8c2eb5d727d83ce059a133c26a06a4730f Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 26 Oct 2016 22:39:27 -0700 Subject: [PATCH 04/10] cleanup --- src/Controllers/PushController.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Controllers/PushController.js b/src/Controllers/PushController.js index ea790573fd..84e2a79d4b 100644 --- a/src/Controllers/PushController.js +++ b/src/Controllers/PushController.js @@ -93,8 +93,6 @@ export class PushController extends AdaptableController { if (!response.results) { return Promise.reject({error: 'PushController: no results in query'}) } - return response; - }).then((response) => { pushStatus.setRunning(response.results); return this.sendToAdapter(body, response.results, pushStatus, config); }).then((results) => { From 41a6ae59ea0f296fc9933b57c38e73efc9b283c0 Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 26 Oct 2016 22:41:36 -0700 Subject: [PATCH 05/10] tweak --- src/StatusHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StatusHandler.js b/src/StatusHandler.js index 0e3a9fe1d6..55ae25214c 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -47,8 +47,8 @@ function statusHandler(className, database) { function insertPushes(installations, pushStatusObjectId) { // Insert a Push object for each installation we're pushing to + let now = new Date(); let promises = _.map(installations, installation => { - let now = new Date(); let pushObjectId = newObjectId(); let push = { pushObjectId, From 77e5a079256ed17f786e93b490851a40dacf69c6 Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 26 Oct 2016 22:54:12 -0700 Subject: [PATCH 06/10] fix up object insertion --- src/StatusHandler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/StatusHandler.js b/src/StatusHandler.js index 55ae25214c..b60d129a5d 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -51,12 +51,12 @@ function statusHandler(className, database) { let promises = _.map(installations, installation => { let pushObjectId = newObjectId(); let push = { - pushObjectId, + objectId: pushObjectId, createdAt: now, installation: { __type: 'Pointer', className: "_Installation", - objectId: installation.id, + objectId: installation.objectId, }, pushStatus: { __type: 'Pointer', From fd2326e8c4bc786fbc7f9b1686bf30ae36f1b434 Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 26 Oct 2016 22:57:25 -0700 Subject: [PATCH 07/10] string field --- src/StatusHandler.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/StatusHandler.js b/src/StatusHandler.js index b60d129a5d..9621ead011 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -58,11 +58,7 @@ function statusHandler(className, database) { className: "_Installation", objectId: installation.objectId, }, - pushStatus: { - __type: 'Pointer', - className: className, - objectId: pushStatusObjectId, - } + pushStatus: pushStatusObjectId }; return createPush(push); }); From e37e32d356a677a2ad895064f4f234d7edad6c5b Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 2 Nov 2016 15:46:05 -0700 Subject: [PATCH 08/10] Push records are now updated after transmission --- src/Controllers/PushController.js | 10 ++++- src/StatusHandler.js | 68 +++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/Controllers/PushController.js b/src/Controllers/PushController.js index 84e2a79d4b..f406456a08 100644 --- a/src/Controllers/PushController.js +++ b/src/Controllers/PushController.js @@ -93,8 +93,14 @@ export class PushController extends AdaptableController { if (!response.results) { return Promise.reject({error: 'PushController: no results in query'}) } - pushStatus.setRunning(response.results); - return this.sendToAdapter(body, response.results, pushStatus, config); + let installations = response.results; + pushStatus.setRunning(installations); + return this.sendToAdapter(body, response.results, pushStatus, config).then((results) => { + return { + installations, + results + }; + }); }).then((results) => { return pushStatus.complete(results); }).catch((err) => { diff --git a/src/StatusHandler.js b/src/StatusHandler.js index 9621ead011..5caeba5489 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -45,7 +45,16 @@ function statusHandler(className, database) { return lastPromise; } - function insertPushes(installations, pushStatusObjectId) { + function updatePush(query, updateFields) { + lastPromise = lastPromise.then(() => { + return database.update(PUSH_COLLECTION, query, updateFields); + }); + return lastPromise; + } + + function insertPushes(pushStatusObjectId, installations) { + console.log('insertPushes'); // For debugging, remove + // Insert a Push object for each installation we're pushing to let now = new Date(); let promises = _.map(installations, installation => { @@ -53,6 +62,8 @@ function statusHandler(className, database) { let push = { objectId: pushObjectId, createdAt: now, + updatedAt: now, + deviceToken: installation.deviceToken, installation: { __type: 'Pointer', className: "_Installation", @@ -65,14 +76,53 @@ function statusHandler(className, database) { return Promise.all(promises); } - function updatePushes(pushStatusObjectId, results) { - return Promise.resolve(); + function updatePushes(pushStatusObjectId, installations, results) { + console.log('updatePushes'); // For debugging, remove + let now = new Date(); + + // For debugging, remove + _.forEach(results, result => { + console.log('result', result); + }); + + let resultsByDeviceToken = _.keyBy(results, r => r.device.deviceToken); + + // Update the push record for each installation + let promises = _.map(installations, installation => { + let deviceToken = installation.deviceToken; + let result = null; + + // Handle different failure scenarios + if (!deviceToken) { + result = { transmitted: false, error: 'No deviceToken found on installation' } + } else if (deviceToken in resultsByDeviceToken) { + result = resultsByDeviceToken[deviceToken]; + } else { + result = { transmitted: false, error: 'No result from adapter' } + } + + // Find the record to update + let query = { + pushStatus: pushStatusObjectId, + installation: { + __type: 'Pointer', + className: "_Installation", + objectId: installation.objectId, + } + }; + let updateFields = { result: result, updatedAt: now }; + + return updatePush(query, updateFields); + }); + + return Promise.all(promises); } return Object.freeze({ create, update, createPush, + updatePush, insertPushes, updatePushes }) @@ -176,13 +226,15 @@ export function pushStatusHandler(config) { let setRunning = function(installations) { logger.verbose('sending push to %d installations', installations.length); - return handler.insertPushes(installations, objectId).then(() => { + return handler.insertPushes(objectId, installations).then(() => { return handler.update({status:"pending", objectId: objectId}, {status: "running", updatedAt: new Date() }); }); } - let complete = function(results) { + let complete = function(data) { + let results = data.results; + let installations = data.installations; let update = { status: 'succeeded', updatedAt: new Date(), @@ -213,10 +265,8 @@ export function pushStatusHandler(config) { }, update); } logger.verbose('sent push! %d success, %d failures', update.numSent, update.numFailed); - return handler.update({status:"running", objectId }, update).then((result) => { - return handler.updatePushes(objectId, results).then(() => { - return result; - }); + return handler.updatePushes(objectId, installations, results).then(() => { + return handler.update({status:"running", objectId }, update); }); } From 1cf005ec5692e6ce69d62f2b4607951b65503ac4 Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 2 Nov 2016 15:46:36 -0700 Subject: [PATCH 09/10] remove logging --- src/StatusHandler.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/StatusHandler.js b/src/StatusHandler.js index 5caeba5489..c8a0d99f07 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -53,8 +53,6 @@ function statusHandler(className, database) { } function insertPushes(pushStatusObjectId, installations) { - console.log('insertPushes'); // For debugging, remove - // Insert a Push object for each installation we're pushing to let now = new Date(); let promises = _.map(installations, installation => { @@ -77,14 +75,8 @@ function statusHandler(className, database) { } function updatePushes(pushStatusObjectId, installations, results) { - console.log('updatePushes'); // For debugging, remove let now = new Date(); - // For debugging, remove - _.forEach(results, result => { - console.log('result', result); - }); - let resultsByDeviceToken = _.keyBy(results, r => r.device.deviceToken); // Update the push record for each installation From 01dea53fbea196999cd699b46d9f120533ac4a53 Mon Sep 17 00:00:00 2001 From: Alex Black Date: Wed, 2 Nov 2016 17:19:46 -0700 Subject: [PATCH 10/10] tests pass --- spec/helper.js | 2 +- src/Controllers/SchemaController.js | 10 +++++++-- src/StatusHandler.js | 33 +++++++++++++++-------------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/spec/helper.js b/spec/helper.js index 142bd8e670..cc42638df3 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -219,7 +219,7 @@ afterEach(function(done) { } else { // Other system classes will break Parse.com, so make sure that we don't save anything to _SCHEMA that will // break it. - return ['_User', '_Installation', '_Role', '_Session', '_Product'].indexOf(className) >= 0; + return ['_User', '_Installation', '_Role', '_Session', '_Product', '_Push'].indexOf(className) >= 0; } }}); }); diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index 316d3da362..09ae2ad706 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -73,6 +73,12 @@ const defaultColumns = Object.freeze({ "title": {type:'String'}, "subtitle": {type:'String'}, }, + _Push: { + "result": {type:'Object'}, + "pushStatus": {type:'String'}, + "installation": {type:'Pointer', targetClass:'_Installation'}, + "deviceToken": {type:'String'}, + }, _PushStatus: { "pushTime": {type:'String'}, "source": {type:'String'}, // rest or webui @@ -113,9 +119,9 @@ const requiredColumns = Object.freeze({ _Role: ["name", "ACL"] }); -const systemClasses = Object.freeze(['_User', '_Installation', '_Role', '_Session', '_Product', '_PushStatus', '_JobStatus']); +const systemClasses = Object.freeze(['_User', '_Installation', '_Role', '_Session', '_Product', '_Push', '_PushStatus', '_JobStatus']); -const volatileClasses = Object.freeze(['_JobStatus', '_PushStatus', '_Hooks', '_GlobalConfig']); +const volatileClasses = Object.freeze(['_JobStatus', '_PushStatus', '_Push', '_Hooks', '_GlobalConfig']); // 10 alpha numberic chars + uppercase const userIdRegex = /^[a-zA-Z0-9]{10}$/; diff --git a/src/StatusHandler.js b/src/StatusHandler.js index c8a0d99f07..1e635f6c97 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -4,7 +4,7 @@ import _ from 'lodash'; const PUSH_STATUS_COLLECTION = '_PushStatus'; const JOB_STATUS_COLLECTION = '_JobStatus'; -const PUSH_COLLECTION = 'Push'; +const PUSH_COLLECTION = '_Push'; export function flatten(array) { return array.reduce((memo, element) => { @@ -37,19 +37,13 @@ function statusHandler(className, database) { } function createPush(object) { - lastPromise = lastPromise.then(() => { - return database.create(PUSH_COLLECTION, object).then(() => { - return Promise.resolve(object); - }); + return database.create(PUSH_COLLECTION, object).then(() => { + return Promise.resolve(object); }); - return lastPromise; } function updatePush(query, updateFields) { - lastPromise = lastPromise.then(() => { - return database.update(PUSH_COLLECTION, query, updateFields); - }); - return lastPromise; + return database.update(PUSH_COLLECTION, query, updateFields); } function insertPushes(pushStatusObjectId, installations) { @@ -102,7 +96,10 @@ function statusHandler(className, database) { objectId: installation.objectId, } }; - let updateFields = { result: result, updatedAt: now }; + let updateFields = { + result: result, + updatedAt: now + }; return updatePush(query, updateFields); }); @@ -218,9 +215,11 @@ export function pushStatusHandler(config) { let setRunning = function(installations) { logger.verbose('sending push to %d installations', installations.length); - return handler.insertPushes(objectId, installations).then(() => { - return handler.update({status:"pending", objectId: objectId}, - {status: "running", updatedAt: new Date() }); + return handler.update({status:"pending", objectId: objectId}, + {status: "running", updatedAt: new Date() }).then((result) => { + return handler.insertPushes(objectId, installations).then(() => { + return result; + }); }); } @@ -257,8 +256,10 @@ export function pushStatusHandler(config) { }, update); } logger.verbose('sent push! %d success, %d failures', update.numSent, update.numFailed); - return handler.updatePushes(objectId, installations, results).then(() => { - return handler.update({status:"running", objectId }, update); + return handler.update({status:"running", objectId }, update).then((result) => { + return handler.updatePushes(objectId, installations, results).then(() => { + return result; + }); }); }